Introduction

In this project, regression models for three different times series data will be built. These data are collected from Central Bank of the Republic of Turkey. the chosen data are:

All of these data are monthly and we have the time series for them from 01-2014 to 01-2024. Therefore they can be plotted against themselves.

The basic approach to the problem is like this: We ask ourselves what could these forecast variables be related to?

After finding the potential answers, these answers are searched in Google trends data and downloaded. Also the time series plot is observed in order to see any trend or seasonality and add them as predictors as well.

After the predictors are decided on several models are built by using all of them and removing some of them. then these models are compared using tests such as AIC or adjusted R squared.

After deciding on which predictors to use, we can proceed with our final decided model. The final decided model is plotted agains the real data in order to see how good the model is.

Finally, the residuals are evaluated. In this part, we try to answer whether our assumptions about the residuals are correct. These are:

If all three of these apply then we can conclude that we have a decent model.

Firstly require the necessary libraries and set the plot window, height and width.

require(data.table)
Loading required package: data.table
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
data.table 1.15.2 using 1 threads (see ?getDTthreads).  Latest news: r-datatable.com
**********
This installation of data.table has not detected OpenMP support. It should still work but in single-threaded mode.
This is a Mac. Please read https://mac.r-project.org/openmp/. Please engage with Apple and ask them for support. Check r-datatable.com for updates, and our Mac instructions here: https://github.com/Rdatatable/data.table/wiki/Installation. After several years of many reports of installation problems on Mac, it's time to gingerly point out that there have been no similar problems on Windows or Linux.
**********
require(lubridate)
Loading required package: lubridate

Attaching package: ‘lubridate’

The following objects are masked from ‘package:data.table’:

    hour, isoweek, mday, minute, month, quarter, second, wday, week, yday, year

The following objects are masked from ‘package:base’:

    date, intersect, setdiff, union
require(forecast)
Loading required package: forecast
require(skimr)
Loading required package: skimr
Registered S3 methods overwritten by 'htmltools':
  method               from         
  print.html           tools:rstudio
  print.shiny.tag      tools:rstudio
  print.shiny.tag.list tools:rstudio
require(repr)
Loading required package: repr
require(readxl)
Loading required package: readxl
require(ggplot2)
Loading required package: ggplot2
Want to understand how all the pieces fit together? Read R for Data Science:
https://r4ds.hadley.nz/
options(repr.plot.width=12.7, repr.plot.height=8.5)

Create data tables for our three forecast variables.

data_path_unemployment ='/Users/ahmetkarakose/Desktop/EVDS.xlsx'
unemployment_data = read_excel(data_path)
New names:
data_path_housing = '/Users/ahmetkarakose/Desktop/konut_fiyat.xlsx'
house_index_data = read_excel(data_path_housing)
New names:
data_path_confidence = '/Users/ahmetkarakose/Desktop/confidence.xlsx'
confidence = read_excel(data_path_confidence)
New names:

Manipulate and clean the data, so it’s at a desired format. Make the forecast values as type numeric. Rename the forecast variable column to a more readable title and make the date column as date type.

Also, create a combined version of these three data.

unemployment_data <- unemployment_data[-(122:133),]
unemployment_data <- unemployment_data[,-3]
unemployment_data$"TP YISGUCU2 G8"  <- as.numeric(unemployment_data$"TP YISGUCU2 G8")
names(unemployment_data)[names(unemployment_data) == "TP YISGUCU2 G8"] <- "Unemployment"
unemployment_data$Date <- paste(unemployment_data$Date, "-01", sep = "")
unemployment_data$Date <- as.Date(unemployment_data$Date)

house_index_data <- house_index_data[-(122:133),]
house_index_data <- house_index_data[,-3]
house_index_data$"TP HKFE01"  <- as.numeric(house_index_data$"TP HKFE01")
names(house_index_data)[names(house_index_data) == "TP HKFE01"] <- "House Price Index"
house_index_data$Tarih <- paste(house_index_data$Tarih, "-01", sep = "")
house_index_data$Tarih <- as.Date(house_index_data$Tarih)

confidence <- confidence[-(122:133),]
confidence <- confidence[,-3]
confidence$"TP GY1 N2"  <- as.numeric(confidence$"TP GY1 N2")
names(confidence)[names(confidence) == "TP GY1 N2"] <- "Real Sector Confidence Index"
confidence$Date <- paste(confidence$Date, "-01", sep = "")
confidence$Date <- as.Date(confidence$Date)

combined <- cbind(unemployment_data[,2], house_index_data[,2], confidence[,2])
combined

In order to see the correlation between data, plot each forecast variable agains the other one and see their correlation values. They need to be less than 0.5 in order to proceed with these forecast varaibles.

As it can be seen below the correlations are:

require(GGally)
Loading required package: GGally
Registered S3 method overwritten by 'GGally':
  method from   
  +.gg   ggplot2
ggpairs(combined)

Unemployment

Firstly, the regression model for the Unemployment data will be built.

Below is the Unemployment vs. Time graph. We can make some deductions out of it:

time_data <- c(year(min(unemployment_data$Date)), month(min(unemployment_data$Date)))
unemployment_ts <- ts(unemployment_data$Unemployment, start = time_data, frequency = 12)

autoplot(unemployment_ts) + ggtitle("Unemployment (%) vs Time") + xlab("Year") + ylab("Unemployment (%)")

When we observe the ACF function for the time series we can observe an increase in lag-12 and lag-24. This proves there is seasonality in data.

ggAcf(unemployment_ts, lag.max = 48) + ggtitle("Unemployment ACF")

Now, we want to find predictors from Google Trends that can be somehow related with the Unemployment in Turkey. When keywords for this relation is thought for, these keywords are found to be logical and related with Unemployment:

It should be noted that maybe the lagged values of these data can be better predictors because, people would search these terms after Unemployment increases. These search terms are results, so the affects of these search terms may be delayed.

Below all of the data is gathered and time series objects are formed. All potential predictor data are plotted and a combination of the potentil predictors are combined. These predictors are also combined within another dataframe.

kredi = fread("/Users/ahmetkarakose/Desktop/kredi.csv")
names(kredi)[names(kredi) == "kredi: (Türkiye)"] <- "Kredi"
kredi_ts <- ts(credit_data[,-1], start = time_data, frequency = 12)

is_ilani = fread("/Users/ahmetkarakose/Desktop/is_ilani.csv")
names(is_ilani)[names(is_ilani) == "iş ilanı: (Türkiye)"] <- "İş ilanı"
is_ilani_ts <- ts(is_ilani[,-1], start = time_data, frequency = 12)

issizlik = fread("/Users/ahmetkarakose/Desktop/issizlik.csv")
names(issizlik)[names(issizlik) == "işsizlik: (Türkiye)"] <- "İşsizlik"
issizlik_ts <- ts(issizlik[,-1], start = time_data, frequency = 12)

mulakat = fread("/Users/ahmetkarakose/Desktop/mulakat.csv")
names(mulakat)[names(mulakat) == "mülakat: (Türkiye)"] <- "Mülakat"
mulakat_ts <- ts(interview_data[,-1], start = time_data, frequency = 12)

autoplot(kredi_ts)

autoplot(is_ilani_ts)

autoplot(issizlik_ts)

autoplot(mulakat_ts)


predictors_unemployment <- cbind(kredi[,-1], is_ilani[,-1], issizlik[,-1], mulakat[,-1])
df_unemployment <- cbind(unemployment_data, predictors)

Below is the correlations between each predictors and the forecast variable. The relations of each of them can be observed below.

require(GGally)
ggpairs(df[,-1])

Now, it’s time to create the model. Firstly the lagged dataframes for all of the selected predictors are created (google trends data). This is to compare the lagged models without the lagged model. Then the piecewise linear trend is formed. In the model seasonal dummy variables are also added. Three possible models are created:

The best one will be evaluated based on the lowest AIC value. As it can be seen below, the lowest AIC value is the one with no_lag. We will proceed with this model in the upcoming comparisons.

library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:data.table’:

    between, first, last

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
kredi_lag <- mutate(kredi,
               kredi_lag1 = lag(kredi$Kredi, 1),  # Lag 1
               kredi_lag2 = lag(kredi$Kredi, 2),  # Lag 2
               )

is_ilani_lag <- mutate(is_ilani,
               is_ilani_lag1 = lag(is_ilani$"İş ilanı", 1),  # Lag 1
               is_ilani_lag2 = lag(is_ilani$"İş ilanı", 2),  # Lag 2
               )

issizlik_lag <- mutate(issizlik,
               issizlik_lag1 = lag(issizlik$"İşsizlik", 1),  # Lag 1
               issizlik_lag2 = lag(issizlik$"İşsizlik", 2),  # Lag 2
               )

mulakat_lag <- mutate(mulakat,
               mulakat_lag1 = lag(mulakat$"Mülakat", 1),  # Lag 1
               mulakat_lag2 = lag(mulakat$"Mülakat", 2),  # Lag 2
               )

combined_lag <- cbind(kredi_lag, is_ilani_lag, issizlik_lag, mulakat_lag)

t <- time(unemployment_ts)
t.break1 <- 2018
t.break2 <- 2021
tb1 <- ts(pmax(0, t - t.break1), start = 2014, end = 2024, frequency = 12)
tb2 <- ts(pmax(0, t- t.break2), start = 2014, end = 2024, frequency = 12)

fit <- tslm(unemployment_ts ~ t + 
                        tb1 + 
                        tb2 + 
                        seasonaldummy(unemployment_ts) + 
                        kredi_ts + 
                        is_ilani_ts + 
                        issizlik_ts + 
                        mulakat_ts)

fit.lag1 <- tslm(unemployment_ts ~ t + 
                        tb1 + 
                        tb2 + 
                        seasonaldummy(unemployment_ts) + 
                        kredi_lag1 + 
                        is_ilani_lag1 + 
                        issizlik_lag1 + 
                        mulakat_lag1, data = combined_lag)

fit.lag2 <- tslm(unemployment_ts ~ t + 
                        tb1 + 
                        tb2 + 
                        seasonaldummy(unemployment_ts) + 
                        kredi_lag2 + 
                        is_ilani_lag2 + 
                        issizlik_lag2 + 
                        mulakat_lag2, data = combined_lag)

no_lag <- CV(fit)
lag_1 <- CV(fit.lag1)
lag_2 <- CV(fit.lag2)
CV_data <- data.frame(rbind(no_lag, lag_1, lag_2))
CV_data

Now, we will inspect the model further and try to remove the unnecessary predictor. In this case all of the predictors (google trends data) are removed one by one and the models are compared according to AIC values. The lowes AIC value model is: fit.w.o.mulakat. This is the model that doesn’t contain the keyword “Mülakat”. So our final model is chosen and the residual analysis will be proceeded accordingly.

fit.everything <- tslm(unemployment_ts ~ t + 
                        tb1 + 
                        tb2 + 
                        seasonaldummy(unemployment_ts) + 
                        kredi_ts + 
                        is_ilani_ts + 
                        issizlik_ts + 
                        mulakat_ts)

fit.w.o.kredi <- tslm(unemployment_ts ~ t + 
                        tb1 + 
                        tb2 + 
                        seasonaldummy(unemployment_ts) + 
                        is_ilani_ts + 
                        issizlik_ts + 
                        mulakat_ts)

fit.w.o.is_ilani <- tslm(unemployment_ts ~ t + 
                        tb1 + 
                        tb2 + 
                        seasonaldummy(unemployment_ts) + 
                        kredi_ts + 
                        issizlik_ts + 
                        mulakat_ts)

fit.w.o.issizlik <- tslm(unemployment_ts ~ t + 
                        tb1 + 
                        tb2 + 
                        seasonaldummy(unemployment_ts) + 
                        kredi_ts + 
                        is_ilani_ts + 
                        mulakat_ts)

fit.w.o.mulakat <- tslm(unemployment_ts ~ t + 
                        tb1 + 
                        tb2 + 
                        seasonaldummy(unemployment_ts) + 
                        kredi_ts + 
                        is_ilani_ts + 
                        issizlik_ts)

all <- CV(fit.everything)
no_kredi <- CV(fit.w.o.kredi)
no_is_ilani <- CV(fit.w.o.is_ilani)
no_issizlik <- CV(fit.w.o.issizlik)
no_mulakat <- CV(fit.w.o.mulakat)
CV_data <- data.frame(rbind(all, no_kredi, no_is_ilani, nos_issizlik, no_mulakat))
CV_data

The model and the data are plotted in order to see visually how they behave.

autoplot(unemployment_ts, series = "Data") + 
  autolayer(fitted(fit.w.o.mulakat), series = "Model")

From the residual analysis part we can conclude that:

When considering different predictors we can observe that January, February and March seasonal variables are actually not very intuitive as they have high p-values.

When the Residuals vs. Fitted values graph is observed, it can be seen that

Overall, the model seems to be adequate, however there are parts to improve the model, especially in seasonality terms.

checkresiduals(fit.w.o.mulakat)

    Breusch-Godfrey test for serial correlation of order up to 24

data:  Residuals from Linear regression model
LM test = 70.519, df = 24, p-value = 1.824e-06

summary(fit.w.o.mulakat)

Call:
tslm(formula = unemployment_ts ~ t + tb1 + tb2 + seasonaldummy(unemployment_ts) + 
    kredi_ts + is_ilani_ts + issizlik_ts)

Residuals:
     Min       1Q   Median       3Q      Max 
-1.29919 -0.39642 -0.03167  0.31611  1.47718 

Coefficients:
                                    Estimate Std. Error t value Pr(>|t|)    
(Intercept)                       269.180188 165.635826   1.625 0.107190    
t                                  -0.130187   0.082224  -1.583 0.116413    
tb1                                 1.145304   0.145796   7.856 3.99e-12 ***
tb2                                -2.506786   0.144222 -17.381  < 2e-16 ***
seasonaldummy(unemployment_ts)Jan   0.398427   0.268328   1.485 0.140637    
seasonaldummy(unemployment_ts)Feb   0.179399   0.272355   0.659 0.511560    
seasonaldummy(unemployment_ts)Mar  -0.243291   0.269573  -0.903 0.368896    
seasonaldummy(unemployment_ts)Apr  -0.648698   0.273610  -2.371 0.019605 *  
seasonaldummy(unemployment_ts)May  -1.196011   0.270638  -4.419 2.46e-05 ***
seasonaldummy(unemployment_ts)Jun  -1.385335   0.271883  -5.095 1.58e-06 ***
seasonaldummy(unemployment_ts)Jul  -0.674922   0.272590  -2.476 0.014917 *  
seasonaldummy(unemployment_ts)Aug  -0.982152   0.281191  -3.493 0.000706 ***
seasonaldummy(unemployment_ts)Sep  -1.153377   0.283378  -4.070 9.23e-05 ***
seasonaldummy(unemployment_ts)Oct  -0.884140   0.278069  -3.180 0.001949 ** 
seasonaldummy(unemployment_ts)Nov  -0.663254   0.273271  -2.427 0.016956 *  
kredi_ts                            0.014996   0.009023   1.662 0.099580 .  
is_ilani_ts                         0.058080   0.006534   8.889 2.17e-14 ***
issizlik_ts                         0.018478   0.008574   2.155 0.033474 *  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.6008 on 103 degrees of freedom
Multiple R-squared:  0.8802,    Adjusted R-squared:  0.8605 
F-statistic: 44.53 on 17 and 103 DF,  p-value: < 2.2e-16
residual_fitted <- data.frame(cbind(Fitted = fitted(fit.w.o.mulakat), Residuals=residuals(fit.w.o.mulakat)))
ggplot(residual_fitted, aes(x = Fitted, y = Residuals)) + geom_point() + ggtitle("Residuals vs. Fitted Values")

House Price Index

In order to get a more real House Price Index, the data is divided to US dollar in order to get the quantities in dollars.

Seasonality can be observed especially at the time between 2014 and 2018.

There is a clear downward trend from 2014 to 2018 and an upward trend from 2022 to 2024.

time_data_house <- c(year(min(house_index_data$Tarih)), month(min(house_index_data$Tarih)))

dollar_datapath = '/Users/ahmetkarakose/Desktop/dolar.xlsx'
dollar_data = read_excel(dollar_datapath)
New names:
dollar_data <- dollar_data[-(122:133),]
dollar_data <- dollar_data[,-3]
dollar_data$"TP DK USD A YTL"  <- as.numeric(dollar_data$"TP DK USD A YTL")
names(dollar_data)[names(dollar_data) == "TP DK USD A YTL"] <- "Dollar"
dollar_data$Tarih <- paste(dollar_data$Tarih, "-01", sep = "")
dollar_data$Tarih <- as.Date(dollar_data$Tarih)

house_index_data[,2] <- house_index_data[,2] / dollar_data[,2]

house_index_ts <- ts(house_index_data$`House Price Index`, start = time_data, frequency = 12)

autoplot(house_index_ts) + ggtitle("House Price Index vs Time") + xlab("Year") + ylab("House Index 2017 = 100")

Let’s look at the autocorrelation function of the time series in order to check seasonality. The ACF does not show any clear pattern of seasonality in this case.

Acf(house_index_ts, lag.max = 24)

Now, we want to find predictors from Google Trends that can be somehow related with the House Price Index in Turkey. When keywords for this relation is thought for, these keywords are found to be logical and related with House Price Index:

It should be noted that maybe the lagged values of these data can be better predictors because, people may search these terms after the House Price Index increases. These search terms are results, so the affects of these search terms may be delayed.

Below all of the data is gathered and time series objects are formed. All potential predictor data are plotted and a combination of the potential predictors are combined. These predictors are also combined within another data frame.

satilik_daire = fread("/Users/ahmetkarakose/Desktop/satilik_daire.csv")
names(satilik_daire)[names(satilik_daire) == "satılık daire: (Türkiye)"] <- "Satılık daire"
satilik_daire_ts <- ts(satilik_daire[,-1], start = time_data, frequency = 12)

faiz = fread("/Users/ahmetkarakose/Desktop/faiz.csv")
names(faiz)[names(faiz) == "faiz: (Türkiye)"] <- "Faiz"
faiz_ts <- ts(faiz[,-1], start = time_data, frequency = 12)

emlak = fread("/Users/ahmetkarakose/Desktop/emlak.csv")
names(emlak)[names(emlak) == "emlak: (Türkiye)"] <- "Emlak"
emlak_ts <- ts(emlak[,-1], start = time_data, frequency = 12)

ipotek = fread("/Users/ahmetkarakose/Desktop/ipotek.csv")
names(ipotek)[names(ipotek) == "ipotek: (Türkiye)"] <- "İpotek"
ipotek_ts <- ts(ipotek[,-1], start = time_data, frequency = 12)

autoplot(satilik_daire_ts)

autoplot(faiz_ts)

autoplot(emlak_ts)

autoplot(ipotek_ts)



predictors_hp_index <- cbind(satilik_daire[,-1], faiz[,-1], emlak[,-1], ipotek[,-1])
df_hp_index <- cbind(house_index_data, predictors_hp_index)

Below is the correlations between each predictors and the forecast variable. The relations of each of them can be observed below.

require(GGally)
ggpairs(df_hp_index[,-1])

Now, it’s time to create the model. Firstly the lagged data frames for all of the selected predictors are created (Google trends data). This is to compare the lagged models without the lagged model. Then the piece wise linear trend is formed. Three possible models are created:

The best one will be evaluated based on the lowest AIC value. As it can be seen below, the lowest AIC value is the one with lag-1. We will proceed with this model in the upcoming comparisons.


library(dplyr)
satilik_daire_lag <- mutate(satilik_daire,
               satilik_daire_lag1 = lag(satilik_daire$`Satılık daire`, 1),  # Lag 1
               satilik_daire_lag2 = lag(satilik_daire$`Satılık daire`, 2),  # Lag 2
               )

faiz_lag <- mutate(faiz,
               faiz_lag1 = lag(faiz$Faiz, 1),  # Lag 1
               faiz_lag2 = lag(faiz$Faiz, 2),  # Lag 2
               )

emlak_lag <- mutate(emlak,
               emlak_lag1 = lag(emlak$Emlak, 1),  # Lag 1
               emlak_lag2 = lag(emlak$Emlak, 2),  # Lag 2
               )

ipotek_lag <- mutate(ipotek,
               ipotek_lag1 = lag(ipotek$İpotek, 1),  # Lag 1
               ipotek_lag2 = lag(ipotek$İpotek, 2),  # Lag 2
               )

combined_lag <- cbind(satilik_daire_lag, faiz_lag, emlak_lag, ipotek_lag)

t <- time(unemployment_ts)
t.break1 <- 2018
t.break2 <- 2022
tb1 <- ts(pmax(0, t - t.break1), start = 2014, end = 2024, frequency = 12)
tb2 <- ts(pmax(0, t- t.break2), start = 2014, end = 2024, frequency = 12)

fit <- tslm(house_index_ts ~ satilik_daire_ts + 
                        faiz_ts+ 
                        emlak_ts +
                        ipotek_ts + 
                        t +
                        tb1 + 
                        tb2)

fit.lag1 <- tslm(house_index_ts ~ t +
                        tb1 + 
                        tb2 + 
                        satilik_daire_lag1 + 
                        faiz_lag1 + 
                        emlak_lag1 +
                        ipotek_lag1, data = combined_lag)

fit.lag2 <- tslm(house_index_ts ~ t +
                        tb1 + 
                        tb2 + 
                        satilik_daire_lag2 + 
                        faiz_lag2 + 
                        emlak_lag2 +
                        ipotek_lag2, data = combined_lag) 


no_lag <- CV(fit)
lag_1 <- CV(fit.lag1)
lag_2 <- CV(fit.lag2)
CV_data <- data.frame(rbind(no_lag, lag_1, lag_2))
CV_data

Now, we will inspect the model further and try to remove the unnecessary predictor. In this case all of the predictors (Google trends data) are removed one by one and the models are compared according to AIC values. The lowest AIC value model is: fit.w.o.emlak. This is the model that doesn’t contain the keyword “Emlak”. So our final model is chosen and the residual analysis will be proceeded accordingly.

fit.everything <- tslm(house_index_ts ~ t +
                        tb1 + 
                        tb2 + 
                        satilik_daire_lag1 + 
                        faiz_lag1 + 
                        emlak_lag1 +
                        ipotek_lag1, data = combined_lag)

fit.w.o.satilik_daire <- tslm(house_index_ts ~ t +
                        tb1 + 
                        tb2 + 
                        faiz_lag1 + 
                        emlak_lag1 +
                        ipotek_lag1, data = combined_lag)

fit.w.o.faiz <- tslm(house_index_ts ~ t +
                        tb1 + 
                        tb2 + 
                        satilik_daire_lag1 + 
                        emlak_lag1 +
                        ipotek_lag1, data = combined_lag)

fit.w.o.emlak <- tslm(house_index_ts ~ t +
                        tb1 + 
                        tb2 + 
                        satilik_daire_lag1 + 
                        faiz_lag1 + 
                        ipotek_lag1, data = combined_lag)

fit.w.o.ipotek <- tslm(house_index_ts ~ t +
                        tb1 + 
                        tb2 + 
                        satilik_daire_lag1 + 
                        faiz_lag1 + 
                        emlak_lag1, data = combined_lag)

all <- CV(fit.everything)
no_satilik_daire <- CV(fit.w.o.satilik_daire)
no_faiz <- CV(fit.w.o.faiz)
no_emlak <- CV(fit.w.o.emlak)
no_ipotek <- CV(fit.w.o.ipotek)
CV_data <- data.frame(rbind(all, no_satilik_daire, no_faiz, no_emlak, no_ipotek))
CV_data

The model and the data are plotted in order to see visually how they behave.

autoplot(house_index_ts, series = "Data") + 
  autolayer(fitted(fit.w.o.emlak), series = "Model")

From the residual analysis part we can conclude that:

When considering different predictors we can observe that tb1 variable is actually not very intuitive as it has a very high p-value.

When the Residuals vs. Fitted values graph is observed, it can be seen that the residuals are kind of scattered around

Overall, the model seems to be adequate, however there are parts to improve the model, especially in trend terms.

summary(fit.w.o.emlak)

Call:
tslm(formula = house_index_ts ~ t + tb1 + tb2 + satilik_daire_lag1 + 
    faiz_lag1 + ipotek_lag1, data = combined_lag)

Residuals:
    Min      1Q  Median      3Q     Max 
-4.7987 -1.2358  0.2498  1.1020  6.3676 

Coefficients:
                     Estimate Std. Error t value Pr(>|t|)    
(Intercept)        2821.06579  459.52141   6.139 1.26e-08 ***
t                    -1.38385    0.22807  -6.068 1.77e-08 ***
tb1                   0.20114    0.39902   0.504  0.61518    
tb2                  17.25767    0.76319  22.613  < 2e-16 ***
satilik_daire_lag1    0.13922    0.02604   5.346 4.74e-07 ***
faiz_lag1            -0.12792    0.01565  -8.174 4.84e-13 ***
ipotek_lag1          -0.09224    0.03070  -3.005  0.00328 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 2.017 on 113 degrees of freedom
  (1 observation deleted due to missingness)
Multiple R-squared:  0.9105,    Adjusted R-squared:  0.9058 
F-statistic: 191.7 on 6 and 113 DF,  p-value: < 2.2e-16
checkresiduals(fit.w.o.emlak)

    Breusch-Godfrey test for serial correlation of order up to 24

data:  Residuals from Linear regression model
LM test = 62.284, df = 24, p-value = 3.019e-05

residual_fitted <- data.frame(cbind(Fitted = fitted(fit.w.o.emlak), Residuals=residuals(fit.w.o.emlak)))
ggplot(residual_fitted, aes(x = Fitted, y = Residuals)) + geom_point() + ggtitle("Residuals vs. Fitted Values")

Real Sector Confidence

Lastly, the regression model for the Real Sector Confidence data will be built.

Below is the Real Sector Confidence vs. Time graph. We can make some deductions out of it:

confidence_ts <- ts(confidence$"Real Sector Confidence Index", start = time_data, frequency = 12)
data.frame(confidence_ts)

autoplot(confidence_ts) + ggtitle("Real Sector Confidence vs Time") + xlab("Year") + ylab("Confidence")

Let’s look at the autocorrelation function of the time series in order to check seasonality. The ACF does not show any clear pattern of seasonality in this case.

ggAcf(confidence_ts, lag.max = 48)

Now, we want to find predictors from Google Trends that can be somehow related with the Real Sector Confidence in Turkey. When keywords for this relation is thought for, these keywords are found to be logical and related with Real Sector Confidence

It should be noted that maybe the lagged values of these data can be better predictors because, people may search these terms after the Real Sector Confidence changes These search terms are results, so the affects of these search terms may be delayed.

Below all of the data is gathered and time series objects are formed. All potential predictor data are plotted and a combination of the potential predictors are combined. These predictors are also combined within another data frame.

Also a time series for corona-start dummy variable is created

ticaret = fread("/Users/ahmetkarakose/Desktop/ticaret.csv")
names(ticaret)[names(ticaret) == "ticaret: (Türkiye)"] <- "Ticaret"
ticaret_ts <- ts(ticaret[,-1], start = time_data, frequency = 12)

uretim = fread("/Users/ahmetkarakose/Desktop/uretim.csv")
names(uretim)[names(uretim) == "üretim: (Türkiye)"] <- "Üretim"
uretim_ts <- ts(uretim[,-1], start = time_data, frequency = 12)

istihdam = fread("/Users/ahmetkarakose/Desktop/istihdam.csv")
names(istihdam)[names(istihdam) == "istihdam: (Türkiye)"] <- "İstihdam"
istihdam_ts <- ts(istihdam[,-1], start = time_data, frequency = 12)

corona_values <- rep(0, 121)
corona_values[75] <- 1
corona_ts <- ts(corona_values, start = c(2014, 1), frequency = 12)

autoplot(faiz_ts)

autoplot(ticaret_ts)

autoplot(uretim_ts)

autoplot(istihdam_ts)

autoplot(corona_ts)


predictors_confidence <- cbind(faiz[,-1], ticaret[,-1], uretim[,-1], istihdam[,-1])
df_confidence <- cbind(confidence, predictors_confidence)

Below is the correlations between each predictors and the forecast variable. The relations of each of them can be observed below.

require(GGally)
ggpairs(df_confidence[,-1])

We were not able to decide whether seasnality and trend were necessary. Apparently the adjusted R^2 value tells us to add seasnoality and trend as predictors

fit <- tslm(confidence_ts ~ faiz_ts + 
                        ticaret_ts + 
                        uretim_ts + 
                        istihdam_ts + 
                        corona_ts + 
                        t + 
                        season)

fit.season <- tslm(confidence_ts ~ faiz_ts + 
                        ticaret_ts + 
                        uretim_ts + 
                        istihdam_ts + 
                        corona_ts + 
                        season)

fit.trend <- tslm(confidence_ts ~ faiz_ts + 
                        ticaret_ts + 
                        uretim_ts + 
                        istihdam_ts + 
                        corona_ts + 
                        t)
fit.none <- tslm(confidence_ts ~ faiz_ts + 
                        ticaret_ts + 
                        uretim_ts + 
                        istihdam_ts + 
                        corona_ts)

no_season_no_trend <- CV(fit.trend)
season_no_trend <- CV(fit.season)
trend_no_season <- CV(fit.trend)
all <- CV(fit)
CV_data <- data.frame(rbind(no_season_no_trend, season_no_trend, trend_no_season, all))
CV_data

Nowi the lagged data frames for all of the selected predictors are created (Google trends data). This is to compare the lagged models without the lagged model. Then the piece wise linear trend is formed. Three possible models are created:

The best one will be evaluated based on the lowest AIC value. As it can be seen below, the lowest AIC value is the one with no lag. We will proceed with this model in the upcoming comparisons.

library(dplyr)

faiz_lag <- mutate(faiz,
               faiz_lag1 = lag(faiz$Faiz, 1),  # Lag 1
               faiz_lag2 = lag(faiz$Faiz, 2),  # Lag 2
               )

ticaret_lag <- mutate(ticaret,
               ticaret_lag1 = lag(ticaret$Ticaret, 1),  # Lag 1
               ticaret_lag2 = lag(ticaret$Ticaret, 2),  # Lag 2
               )

uretim_lag <- mutate(uretim,
               uretim_lag1 = lag(uretim$Üretim, 1),  # Lag 1
               uretim_lag2 = lag(uretim$Üretim, 2),  # Lag 2
               )

istihdam_lag <- mutate(istihdam,
               istihdam_lag1 = lag(istihdam$İstihdam, 1),  # Lag 1
               istihdam_lag2 = lag(istihdam$İstihdam, 2),  # Lag 2
               )

combined_lag <- cbind(faiz_lag, ticaret_lag, uretim_lag, istihdam_lag)

fit <- tslm(confidence_ts ~ faiz_ts + 
                        ticaret_ts + 
                        uretim_ts + 
                        istihdam_ts + 
                        corona_ts + 
                        t + 
                        season)

fit.lag1 <- tslm(confidence_ts ~ t + 
                        season + 
                        faiz_lag1 + 
                        ticaret_lag1 + 
                        uretim_lag1 + 
                        istihdam_lag1, data = combined_lag)

fit.lag2 <- tslm(confidence_ts ~ t + 
                        season + 
                        faiz_lag2 + 
                        ticaret_lag2 + 
                        uretim_lag2 + 
                        istihdam_lag2, data = combined_lag)

no_lag <- CV(fit)
lag_1 <- CV(fit.lag1)
lag_2 <- CV(fit.lag2)
CV_data <- data.frame(rbind(no_lag, lag_1, lag_2))
CV_data

Now, we will inspect the model further and try to remove the unnecessary predictor. In this case all of the predictors (Google trends data) are removed one by one and the models are compared according to AIC and adj. R^2 values. The best models are fit.everything and fit.w.o.corona respectively for adj. R^2 value and AIC value. We will proceed with fit.everything

fit.everything <- tslm(confidence_ts ~ faiz_ts + 
                        ticaret_ts + 
                        uretim_ts + 
                        istihdam_ts + 
                        corona_ts + 
                        t + 
                        season)

fit.w.o.faiz <- tslm(confidence_ts ~ ticaret_ts + 
                        uretim_ts + 
                        istihdam_ts + 
                        corona_ts + 
                        t + 
                        season)

fit.w.o.ticaret <- tslm(confidence_ts ~ faiz_ts + 
                        uretim_ts + 
                        istihdam_ts + 
                        corona_ts + 
                        t + 
                        season)

fit.w.o.uretim <- tslm(confidence_ts ~ faiz_ts + 
                        ticaret_ts + 
                        istihdam_ts + 
                        corona_ts + 
                        t + 
                        season)

fit.w.o.istihdam <- tslm(confidence_ts ~ faiz_ts + 
                        ticaret_ts + 
                        uretim_ts + 
                        corona_ts + 
                        t + 
                        season)

fit.w.o.corona <- tslm(confidence_ts ~ faiz_ts + 
                        ticaret_ts + 
                        uretim_ts + 
                        istihdam_ts + 
                        t + 
                        season)

all <- CV(fit.everything)
no_faiz <- CV(fit.w.o.faiz)
no_ticaret <- CV(fit.w.o.ticaret)
no_uretim <- CV(fit.w.o.uretim)
no_istihdam <- CV(fit.w.o.istihdam)
no_corona <- CV(fit.w.o.corona)
CV_data <- data.frame(rbind(all, no_faiz, no_ticaret, no_uretim, no_istihdam, no_corona))
CV_data

The model and the data are plotted in order to see visually how they behave.

autoplot(confidence_ts, series = "Data") + 
  autolayer(fitted(fit.everything), series = "Model")

From the residual analysis part we can conclude that:

When considering different predictors we can observe that most of the seasonality values are not that informative (We were not sure whether to add to the model)

When the Residuals vs. Fitted values graph is observed, it can be seen that the residuals are kind of scattered around

Overall, the model seems to deosn’t seem adequate as there is really high AC between residuals and the adjusted R^2 value is pretty small.

summary(fit.everything)

Call:
tslm(formula = confidence_ts ~ faiz_ts + ticaret_ts + uretim_ts + 
    istihdam_ts + corona_ts + t + season)

Residuals:
    Min      1Q  Median      3Q     Max 
-13.653  -3.027   0.078   2.875  12.643 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept) -3.961e+03  7.178e+02  -5.518 2.57e-07 ***
faiz_ts     -2.094e-01  4.156e-02  -5.039 2.01e-06 ***
ticaret_ts   2.791e-01  7.225e-02   3.863 0.000196 ***
uretim_ts    7.685e-02  6.997e-02   1.098 0.274595    
istihdam_ts -4.171e-01  5.774e-02  -7.224 9.04e-11 ***
corona_ts   -6.794e+00  5.611e+00  -1.211 0.228731    
t            2.010e+00  3.570e-01   5.629 1.57e-07 ***
season2      1.865e+00  2.279e+00   0.818 0.415120    
season3      6.576e+00  2.391e+00   2.750 0.007035 ** 
season4      5.427e+00  2.348e+00   2.311 0.022808 *  
season5      5.882e+00  2.313e+00   2.543 0.012467 *  
season6      5.242e+00  2.306e+00   2.273 0.025111 *  
season7      2.794e+00  2.478e+00   1.128 0.262144    
season8     -4.489e-01  2.502e+00  -0.179 0.857996    
season9     -1.472e-01  2.565e+00  -0.057 0.954331    
season10    -2.640e-02  2.329e+00  -0.011 0.990978    
season11    -7.249e-01  2.301e+00  -0.315 0.753368    
season12    -1.029e+00  2.277e+00  -0.452 0.652113    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 5.192 on 103 degrees of freedom
Multiple R-squared:  0.5139,    Adjusted R-squared:  0.4337 
F-statistic: 6.406 on 17 and 103 DF,  p-value: 5.08e-10
checkresiduals(fit.everything)

    Breusch-Godfrey test for serial correlation of order up to 24

data:  Residuals from Linear regression model
LM test = 65.874, df = 24, p-value = 9.054e-06

residual_fitted <- data.frame(cbind(Fitted = fitted(fit.everything), Residuals=residuals(fit.everything)))
ggplot(residual_fitted, aes(x = Fitted, y = Residuals)) + geom_point() + ggtitle("Residuals vs. Fitted Values")

Conclusion

Overall, we have built three regression models in three different time series. Even though some of the models were better than the other models there was one common problem: autocorrelation between residuals. In all of the models the ACF graph was not as desired and this remarked further investigation on the model.

However other than this, this assignment tought how to build models, select predictors, compare models and do residual analysis for different time series and was benefitary.

Appendices

ChatGPT:

LS0tCnRpdGxlOiAiSFcxIFRpbWUgU2VyaWVzIFJlZ3Jlc3Npb24iCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIEludHJvZHVjdGlvbgoKSW4gdGhpcyBwcm9qZWN0LCByZWdyZXNzaW9uIG1vZGVscyBmb3IgdGhyZWUgZGlmZmVyZW50IHRpbWVzIHNlcmllcyBkYXRhIHdpbGwgYmUgYnVpbHQuIFRoZXNlIGRhdGEgYXJlIGNvbGxlY3RlZCBmcm9tIENlbnRyYWwgQmFuayBvZiB0aGUgUmVwdWJsaWMgb2YgVHVya2V5LiB0aGUgY2hvc2VuIGRhdGEgYXJlOgoKLSAgIFVuZW1wbG95bWVudCBwZXJjZW50YWdlCi0gICBIb3VzZSBwcmljZSBpbmRleAotICAgUmVhbCBzZWN0b3IgY29uZmlkZW5jZSBpbmRleAoKQWxsIG9mIHRoZXNlIGRhdGEgYXJlIG1vbnRobHkgYW5kIHdlIGhhdmUgdGhlIHRpbWUgc2VyaWVzIGZvciB0aGVtIGZyb20gMDEtMjAxNCB0byAwMS0yMDI0LiBUaGVyZWZvcmUgdGhleSBjYW4gYmUgcGxvdHRlZCBhZ2FpbnN0IHRoZW1zZWx2ZXMuCgpUaGUgYmFzaWMgYXBwcm9hY2ggdG8gdGhlIHByb2JsZW0gaXMgbGlrZSB0aGlzOiBXZSBhc2sgb3Vyc2VsdmVzIHdoYXQgY291bGQgdGhlc2UgZm9yZWNhc3QgdmFyaWFibGVzIGJlIHJlbGF0ZWQgdG8/CgpBZnRlciBmaW5kaW5nIHRoZSBwb3RlbnRpYWwgYW5zd2VycywgdGhlc2UgYW5zd2VycyBhcmUgc2VhcmNoZWQgaW4gR29vZ2xlIHRyZW5kcyBkYXRhIGFuZCBkb3dubG9hZGVkLiBBbHNvIHRoZSB0aW1lIHNlcmllcyBwbG90IGlzIG9ic2VydmVkIGluIG9yZGVyIHRvIHNlZSBhbnkgdHJlbmQgb3Igc2Vhc29uYWxpdHkgYW5kIGFkZCB0aGVtIGFzIHByZWRpY3RvcnMgYXMgd2VsbC4KCkFmdGVyIHRoZSBwcmVkaWN0b3JzIGFyZSBkZWNpZGVkIG9uIHNldmVyYWwgbW9kZWxzIGFyZSBidWlsdCBieSB1c2luZyBhbGwgb2YgdGhlbSBhbmQgcmVtb3Zpbmcgc29tZSBvZiB0aGVtLiB0aGVuIHRoZXNlIG1vZGVscyBhcmUgY29tcGFyZWQgdXNpbmcgdGVzdHMgc3VjaCBhcyBBSUMgb3IgYWRqdXN0ZWQgUiBzcXVhcmVkLgoKQWZ0ZXIgZGVjaWRpbmcgb24gd2hpY2ggcHJlZGljdG9ycyB0byB1c2UsIHdlIGNhbiBwcm9jZWVkIHdpdGggb3VyIGZpbmFsIGRlY2lkZWQgbW9kZWwuIFRoZSBmaW5hbCBkZWNpZGVkIG1vZGVsIGlzIHBsb3R0ZWQgYWdhaW5zIHRoZSByZWFsIGRhdGEgaW4gb3JkZXIgdG8gc2VlIGhvdyBnb29kIHRoZSBtb2RlbCBpcy4KCkZpbmFsbHksIHRoZSByZXNpZHVhbHMgYXJlIGV2YWx1YXRlZC4gSW4gdGhpcyBwYXJ0LCB3ZSB0cnkgdG8gYW5zd2VyIHdoZXRoZXIgb3VyIGFzc3VtcHRpb25zIGFib3V0IHRoZSByZXNpZHVhbHMgYXJlIGNvcnJlY3QuIFRoZXNlIGFyZToKCi0gICBUaGV5IGhhdmUgbWVhbiB6ZXJvCi0gICBEaXN0cmlidXRlZCBhcHByb3hpbWF0ZWx5IG5vcm1hbAotICAgVGhleSBkb24ndCBoYXZlIGF1dG9jb3JyZWxhdGlvbgoKSWYgYWxsIHRocmVlIG9mIHRoZXNlIGFwcGx5IHRoZW4gd2UgY2FuIGNvbmNsdWRlIHRoYXQgd2UgaGF2ZSBhIGRlY2VudCBtb2RlbC4KCkZpcnN0bHkgcmVxdWlyZSB0aGUgbmVjZXNzYXJ5IGxpYnJhcmllcyBhbmQgc2V0IHRoZSBwbG90IHdpbmRvdywgaGVpZ2h0IGFuZCB3aWR0aC4KCmBgYHtyfQpyZXF1aXJlKGRhdGEudGFibGUpCnJlcXVpcmUobHVicmlkYXRlKQpyZXF1aXJlKGZvcmVjYXN0KQpyZXF1aXJlKHNraW1yKQpyZXF1aXJlKHJlcHIpCnJlcXVpcmUocmVhZHhsKQpyZXF1aXJlKGdncGxvdDIpCgoKb3B0aW9ucyhyZXByLnBsb3Qud2lkdGg9MTIuNywgcmVwci5wbG90LmhlaWdodD04LjUpCmBgYAoKQ3JlYXRlIGRhdGEgdGFibGVzIGZvciBvdXIgdGhyZWUgZm9yZWNhc3QgdmFyaWFibGVzLgoKYGBge3J9CmRhdGFfcGF0aF91bmVtcGxveW1lbnQgPScvVXNlcnMvYWhtZXRrYXJha29zZS9EZXNrdG9wL0VWRFMueGxzeCcKdW5lbXBsb3ltZW50X2RhdGEgPSByZWFkX2V4Y2VsKGRhdGFfcGF0aCkKCmRhdGFfcGF0aF9ob3VzaW5nID0gJy9Vc2Vycy9haG1ldGthcmFrb3NlL0Rlc2t0b3Ava29udXRfZml5YXQueGxzeCcKaG91c2VfaW5kZXhfZGF0YSA9IHJlYWRfZXhjZWwoZGF0YV9wYXRoX2hvdXNpbmcpCgpkYXRhX3BhdGhfY29uZmlkZW5jZSA9ICcvVXNlcnMvYWhtZXRrYXJha29zZS9EZXNrdG9wL2NvbmZpZGVuY2UueGxzeCcKY29uZmlkZW5jZSA9IHJlYWRfZXhjZWwoZGF0YV9wYXRoX2NvbmZpZGVuY2UpCgpgYGAKCk1hbmlwdWxhdGUgYW5kIGNsZWFuIHRoZSBkYXRhLCBzbyBpdCdzIGF0IGEgZGVzaXJlZCBmb3JtYXQuIE1ha2UgdGhlIGZvcmVjYXN0IHZhbHVlcyBhcyB0eXBlIG51bWVyaWMuIFJlbmFtZSB0aGUgZm9yZWNhc3QgdmFyaWFibGUgY29sdW1uIHRvIGEgbW9yZSByZWFkYWJsZSB0aXRsZSBhbmQgbWFrZSB0aGUgZGF0ZSBjb2x1bW4gYXMgZGF0ZSB0eXBlLgoKQWxzbywgY3JlYXRlIGEgY29tYmluZWQgdmVyc2lvbiBvZiB0aGVzZSB0aHJlZSBkYXRhLgoKYGBge3J9CnVuZW1wbG95bWVudF9kYXRhIDwtIHVuZW1wbG95bWVudF9kYXRhWy0oMTIyOjEzMyksXQp1bmVtcGxveW1lbnRfZGF0YSA8LSB1bmVtcGxveW1lbnRfZGF0YVssLTNdCnVuZW1wbG95bWVudF9kYXRhJCJUUCBZSVNHVUNVMiBHOCIgIDwtIGFzLm51bWVyaWModW5lbXBsb3ltZW50X2RhdGEkIlRQIFlJU0dVQ1UyIEc4IikKbmFtZXModW5lbXBsb3ltZW50X2RhdGEpW25hbWVzKHVuZW1wbG95bWVudF9kYXRhKSA9PSAiVFAgWUlTR1VDVTIgRzgiXSA8LSAiVW5lbXBsb3ltZW50Igp1bmVtcGxveW1lbnRfZGF0YSREYXRlIDwtIHBhc3RlKHVuZW1wbG95bWVudF9kYXRhJERhdGUsICItMDEiLCBzZXAgPSAiIikKdW5lbXBsb3ltZW50X2RhdGEkRGF0ZSA8LSBhcy5EYXRlKHVuZW1wbG95bWVudF9kYXRhJERhdGUpCgpob3VzZV9pbmRleF9kYXRhIDwtIGhvdXNlX2luZGV4X2RhdGFbLSgxMjI6MTMzKSxdCmhvdXNlX2luZGV4X2RhdGEgPC0gaG91c2VfaW5kZXhfZGF0YVssLTNdCmhvdXNlX2luZGV4X2RhdGEkIlRQIEhLRkUwMSIgIDwtIGFzLm51bWVyaWMoaG91c2VfaW5kZXhfZGF0YSQiVFAgSEtGRTAxIikKbmFtZXMoaG91c2VfaW5kZXhfZGF0YSlbbmFtZXMoaG91c2VfaW5kZXhfZGF0YSkgPT0gIlRQIEhLRkUwMSJdIDwtICJIb3VzZSBQcmljZSBJbmRleCIKaG91c2VfaW5kZXhfZGF0YSRUYXJpaCA8LSBwYXN0ZShob3VzZV9pbmRleF9kYXRhJFRhcmloLCAiLTAxIiwgc2VwID0gIiIpCmhvdXNlX2luZGV4X2RhdGEkVGFyaWggPC0gYXMuRGF0ZShob3VzZV9pbmRleF9kYXRhJFRhcmloKQoKY29uZmlkZW5jZSA8LSBjb25maWRlbmNlWy0oMTIyOjEzMyksXQpjb25maWRlbmNlIDwtIGNvbmZpZGVuY2VbLC0zXQpjb25maWRlbmNlJCJUUCBHWTEgTjIiICA8LSBhcy5udW1lcmljKGNvbmZpZGVuY2UkIlRQIEdZMSBOMiIpCm5hbWVzKGNvbmZpZGVuY2UpW25hbWVzKGNvbmZpZGVuY2UpID09ICJUUCBHWTEgTjIiXSA8LSAiUmVhbCBTZWN0b3IgQ29uZmlkZW5jZSBJbmRleCIKY29uZmlkZW5jZSREYXRlIDwtIHBhc3RlKGNvbmZpZGVuY2UkRGF0ZSwgIi0wMSIsIHNlcCA9ICIiKQpjb25maWRlbmNlJERhdGUgPC0gYXMuRGF0ZShjb25maWRlbmNlJERhdGUpCgpjb21iaW5lZCA8LSBjYmluZCh1bmVtcGxveW1lbnRfZGF0YVssMl0sIGhvdXNlX2luZGV4X2RhdGFbLDJdLCBjb25maWRlbmNlWywyXSkKY29tYmluZWQKYGBgCgpJbiBvcmRlciB0byBzZWUgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gZGF0YSwgcGxvdCBlYWNoIGZvcmVjYXN0IHZhcmlhYmxlIGFnYWlucyB0aGUgb3RoZXIgb25lIGFuZCBzZWUgdGhlaXIgY29ycmVsYXRpb24gdmFsdWVzLiBUaGV5IG5lZWQgdG8gYmUgbGVzcyB0aGFuIDAuNSBpbiBvcmRlciB0byBwcm9jZWVkIHdpdGggdGhlc2UgZm9yZWNhc3QgdmFyYWlibGVzLgoKQXMgaXQgY2FuIGJlIHNlZW4gYmVsb3cgdGhlIGNvcnJlbGF0aW9ucyBhcmU6CgotICAgLTAuMzk4IGZvciBIb3VzZSBQcmljZSBJbmRleCB2cy4gVW5lbXBsb3ltZW50Ci0gICAtMC4zMTAgZm9yIFJlYWwgU2VjdG9yIENvbmZpZGVuY2UgdnMuIFVuZW1wbG95bWVudAotICAgLTAuMDEwIGZvciBSZWFsIFNlY3RvciBDb25maWRlbmNlIHZzLiBIb3VzZSBQcmljZSBJbmRleAoKYGBge3J9CnJlcXVpcmUoR0dhbGx5KQpnZ3BhaXJzKGNvbWJpbmVkKQpgYGAKCiMjIFVuZW1wbG95bWVudAoKRmlyc3RseSwgdGhlIHJlZ3Jlc3Npb24gbW9kZWwgZm9yIHRoZSBVbmVtcGxveW1lbnQgZGF0YSB3aWxsIGJlIGJ1aWx0LgoKQmVsb3cgaXMgdGhlIFVuZW1wbG95bWVudCB2cy4gVGltZSBncmFwaC4gV2UgY2FuIG1ha2Ugc29tZSBkZWR1Y3Rpb25zIG91dCBvZiBpdDoKCi0gICBUaGVyZSBpcyBhbiBvYnZpb3VzIHNlYXNvbmFsaXR5IGJldHdlZW4gMjAxNCAtIDIwMTggYW5kIDIwMjEtMjAyNC4gU28gc2Vhc29uYWxpdHkgY2FuIGJlIGFkZGVkIHRvIG91ciBtb2RlbC4KLSAgIEFsc28gdGhlcmUgaXMgaW5jcmVhc2luZyB0cmVuZCBiZXR3ZWVuIDIwMTQtMjAxOCBhbmQgZGVjcmVhc2luZyB0cmVuZCBiZXR3ZWVuIDIwMjEtMjAyNC4gQSBwaWVjZXdpc2UgdHJlbmQgY291bGQgYmUgYWRkZWQgdG8gb3VyIG1vZGVsLgotICAgVGhlcmUgaXMgYSBzaGFycCBpbmNyZWFzZSBpbiAyMDE5LgoKYGBge3J9CnRpbWVfZGF0YSA8LSBjKHllYXIobWluKHVuZW1wbG95bWVudF9kYXRhJERhdGUpKSwgbW9udGgobWluKHVuZW1wbG95bWVudF9kYXRhJERhdGUpKSkKdW5lbXBsb3ltZW50X3RzIDwtIHRzKHVuZW1wbG95bWVudF9kYXRhJFVuZW1wbG95bWVudCwgc3RhcnQgPSB0aW1lX2RhdGEsIGZyZXF1ZW5jeSA9IDEyKQoKYXV0b3Bsb3QodW5lbXBsb3ltZW50X3RzKSArIGdndGl0bGUoIlVuZW1wbG95bWVudCAoJSkgdnMgVGltZSIpICsgeGxhYigiWWVhciIpICsgeWxhYigiVW5lbXBsb3ltZW50ICglKSIpCmBgYAoKV2hlbiB3ZSBvYnNlcnZlIHRoZSBBQ0YgZnVuY3Rpb24gZm9yIHRoZSB0aW1lIHNlcmllcyB3ZSBjYW4gb2JzZXJ2ZSBhbiBpbmNyZWFzZSBpbiBsYWctMTIgYW5kIGxhZy0yNC4gVGhpcyBwcm92ZXMgdGhlcmUgaXMgc2Vhc29uYWxpdHkgaW4gZGF0YS4KCmBgYHtyfQpnZ0FjZih1bmVtcGxveW1lbnRfdHMsIGxhZy5tYXggPSA0OCkgKyBnZ3RpdGxlKCJVbmVtcGxveW1lbnQgQUNGIikKYGBgCgpOb3csIHdlIHdhbnQgdG8gZmluZCBwcmVkaWN0b3JzIGZyb20gR29vZ2xlIFRyZW5kcyB0aGF0IGNhbiBiZSBzb21laG93IHJlbGF0ZWQgd2l0aCB0aGUgVW5lbXBsb3ltZW50IGluIFR1cmtleS4gV2hlbiBrZXl3b3JkcyBmb3IgdGhpcyByZWxhdGlvbiBpcyB0aG91Z2h0IGZvciwgdGhlc2Uga2V5d29yZHMgYXJlIGZvdW5kIHRvIGJlIGxvZ2ljYWwgYW5kIHJlbGF0ZWQgd2l0aCBVbmVtcGxveW1lbnQ6CgotICAgIktyZWRpIjogTWF5YmUgcGVvcGxlIGFyZSBzZWVraW5nIGZvciBtb3JlIGNyZWRpdHMgd2hlbiB1bmVtcGxveW1lbnQgaW5jcmVhc2VzCi0gICAixLDFnyBpbGFuxLEiOiBQZW9wbGUgbWF5IGJlIHNlZWtpbmcgbW9yZSBqb2JzIHdoZW4gdW5lbXBsb3ltZW50IGluY3JlYXNlcy4KLSAgICLEsMWfc2l6bGlrIjogT2J2aW91c2x5IHBlb3BsZSB3aWxsIHNlYXJjaCB0aGlzIHRlcm0gd2hlbiB1bmVtcGxveW1lbnQgaW5jcmVhc2VzCi0gICAiTcO8bGFrYXQiOiBNYXliZSBwZW9wbGUgYXJlIHNlZWtpbmcgZm9yIG1vcmUgaW50ZXJ2aWV3cyBiZWNhdXNlIHRoZXkgd2FudCB0byBlbnRlciBuZXcgam9icy4KCkl0IHNob3VsZCBiZSBub3RlZCB0aGF0IG1heWJlIHRoZSBsYWdnZWQgdmFsdWVzIG9mIHRoZXNlIGRhdGEgY2FuIGJlIGJldHRlciBwcmVkaWN0b3JzIGJlY2F1c2UsIHBlb3BsZSB3b3VsZCBzZWFyY2ggdGhlc2UgdGVybXMgYWZ0ZXIgVW5lbXBsb3ltZW50IGluY3JlYXNlcy4gVGhlc2Ugc2VhcmNoIHRlcm1zIGFyZSByZXN1bHRzLCBzbyB0aGUgYWZmZWN0cyBvZiB0aGVzZSBzZWFyY2ggdGVybXMgbWF5IGJlIGRlbGF5ZWQuCgpCZWxvdyBhbGwgb2YgdGhlIGRhdGEgaXMgZ2F0aGVyZWQgYW5kIHRpbWUgc2VyaWVzIG9iamVjdHMgYXJlIGZvcm1lZC4gQWxsIHBvdGVudGlhbCBwcmVkaWN0b3IgZGF0YSBhcmUgcGxvdHRlZCBhbmQgYSBjb21iaW5hdGlvbiBvZiB0aGUgcG90ZW50aWwgcHJlZGljdG9ycyBhcmUgY29tYmluZWQuIFRoZXNlIHByZWRpY3RvcnMgYXJlIGFsc28gY29tYmluZWQgd2l0aGluIGFub3RoZXIgZGF0YWZyYW1lLgoKYGBge3J9CmtyZWRpID0gZnJlYWQoIi9Vc2Vycy9haG1ldGthcmFrb3NlL0Rlc2t0b3Ava3JlZGkuY3N2IikKbmFtZXMoa3JlZGkpW25hbWVzKGtyZWRpKSA9PSAia3JlZGk6IChUw7xya2l5ZSkiXSA8LSAiS3JlZGkiCmtyZWRpX3RzIDwtIHRzKGNyZWRpdF9kYXRhWywtMV0sIHN0YXJ0ID0gdGltZV9kYXRhLCBmcmVxdWVuY3kgPSAxMikKCmlzX2lsYW5pID0gZnJlYWQoIi9Vc2Vycy9haG1ldGthcmFrb3NlL0Rlc2t0b3AvaXNfaWxhbmkuY3N2IikKbmFtZXMoaXNfaWxhbmkpW25hbWVzKGlzX2lsYW5pKSA9PSAiacWfIGlsYW7EsTogKFTDvHJraXllKSJdIDwtICLEsMWfIGlsYW7EsSIKaXNfaWxhbmlfdHMgPC0gdHMoaXNfaWxhbmlbLC0xXSwgc3RhcnQgPSB0aW1lX2RhdGEsIGZyZXF1ZW5jeSA9IDEyKQoKaXNzaXpsaWsgPSBmcmVhZCgiL1VzZXJzL2FobWV0a2FyYWtvc2UvRGVza3RvcC9pc3Npemxpay5jc3YiKQpuYW1lcyhpc3NpemxpaylbbmFtZXMoaXNzaXpsaWspID09ICJpxZ9zaXpsaWs6IChUw7xya2l5ZSkiXSA8LSAixLDFn3NpemxpayIKaXNzaXpsaWtfdHMgPC0gdHMoaXNzaXpsaWtbLC0xXSwgc3RhcnQgPSB0aW1lX2RhdGEsIGZyZXF1ZW5jeSA9IDEyKQoKbXVsYWthdCA9IGZyZWFkKCIvVXNlcnMvYWhtZXRrYXJha29zZS9EZXNrdG9wL211bGFrYXQuY3N2IikKbmFtZXMobXVsYWthdClbbmFtZXMobXVsYWthdCkgPT0gIm3DvGxha2F0OiAoVMO8cmtpeWUpIl0gPC0gIk3DvGxha2F0IgptdWxha2F0X3RzIDwtIHRzKGludGVydmlld19kYXRhWywtMV0sIHN0YXJ0ID0gdGltZV9kYXRhLCBmcmVxdWVuY3kgPSAxMikKCmF1dG9wbG90KGtyZWRpX3RzKQphdXRvcGxvdChpc19pbGFuaV90cykKYXV0b3Bsb3QoaXNzaXpsaWtfdHMpCmF1dG9wbG90KG11bGFrYXRfdHMpCgpwcmVkaWN0b3JzX3VuZW1wbG95bWVudCA8LSBjYmluZChrcmVkaVssLTFdLCBpc19pbGFuaVssLTFdLCBpc3Npemxpa1ssLTFdLCBtdWxha2F0WywtMV0pCmRmX3VuZW1wbG95bWVudCA8LSBjYmluZCh1bmVtcGxveW1lbnRfZGF0YSwgcHJlZGljdG9ycykKYGBgCgpCZWxvdyBpcyB0aGUgY29ycmVsYXRpb25zIGJldHdlZW4gZWFjaCBwcmVkaWN0b3JzIGFuZCB0aGUgZm9yZWNhc3QgdmFyaWFibGUuIFRoZSByZWxhdGlvbnMgb2YgZWFjaCBvZiB0aGVtIGNhbiBiZSBvYnNlcnZlZCBiZWxvdy4KCmBgYHtyfQpyZXF1aXJlKEdHYWxseSkKZ2dwYWlycyhkZlssLTFdKQpgYGAKCk5vdywgaXQncyB0aW1lIHRvIGNyZWF0ZSB0aGUgbW9kZWwuIEZpcnN0bHkgdGhlIGxhZ2dlZCBkYXRhZnJhbWVzIGZvciBhbGwgb2YgdGhlIHNlbGVjdGVkIHByZWRpY3RvcnMgYXJlIGNyZWF0ZWQgKGdvb2dsZSB0cmVuZHMgZGF0YSkuIFRoaXMgaXMgdG8gY29tcGFyZSB0aGUgbGFnZ2VkIG1vZGVscyB3aXRob3V0IHRoZSBsYWdnZWQgbW9kZWwuIFRoZW4gdGhlIHBpZWNld2lzZSBsaW5lYXIgdHJlbmQgaXMgZm9ybWVkLiBJbiB0aGUgbW9kZWwgc2Vhc29uYWwgZHVtbXkgdmFyaWFibGVzIGFyZSBhbHNvIGFkZGVkLiBUaHJlZSBwb3NzaWJsZSBtb2RlbHMgYXJlIGNyZWF0ZWQ6CgotICAgZml0OiBVc2luZyBhbGwgdGhlIHByZWRpY3RvcnMKLSAgIGZpdC5sYWcxOiBVc2luZyBhbGwgdGhlIGxhZy0xIHByZWRpY3RvcnMKLSAgIGZpdC5sYWcyOiBVc2luZyBhbGwgdGhlIGxhZy0yIHByZWRpY3RvcnMKClRoZSBiZXN0IG9uZSB3aWxsIGJlIGV2YWx1YXRlZCBiYXNlZCBvbiB0aGUgbG93ZXN0IEFJQyB2YWx1ZS4gQXMgaXQgY2FuIGJlIHNlZW4gYmVsb3csIHRoZSBsb3dlc3QgQUlDIHZhbHVlIGlzIHRoZSBvbmUgd2l0aCBub19sYWcuIFdlIHdpbGwgcHJvY2VlZCB3aXRoIHRoaXMgbW9kZWwgaW4gdGhlIHVwY29taW5nIGNvbXBhcmlzb25zLgoKYGBge3J9CmxpYnJhcnkoZHBseXIpCmtyZWRpX2xhZyA8LSBtdXRhdGUoa3JlZGksCiAgICAgICAgICAgICAgIGtyZWRpX2xhZzEgPSBsYWcoa3JlZGkkS3JlZGksIDEpLCAgIyBMYWcgMQogICAgICAgICAgICAgICBrcmVkaV9sYWcyID0gbGFnKGtyZWRpJEtyZWRpLCAyKSwgICMgTGFnIDIKICAgICAgICAgICAgICAgKQoKaXNfaWxhbmlfbGFnIDwtIG11dGF0ZShpc19pbGFuaSwKICAgICAgICAgICAgICAgaXNfaWxhbmlfbGFnMSA9IGxhZyhpc19pbGFuaSQixLDFnyBpbGFuxLEiLCAxKSwgICMgTGFnIDEKICAgICAgICAgICAgICAgaXNfaWxhbmlfbGFnMiA9IGxhZyhpc19pbGFuaSQixLDFnyBpbGFuxLEiLCAyKSwgICMgTGFnIDIKICAgICAgICAgICAgICAgKQoKaXNzaXpsaWtfbGFnIDwtIG11dGF0ZShpc3NpemxpaywKICAgICAgICAgICAgICAgaXNzaXpsaWtfbGFnMSA9IGxhZyhpc3NpemxpayQixLDFn3NpemxpayIsIDEpLCAgIyBMYWcgMQogICAgICAgICAgICAgICBpc3Npemxpa19sYWcyID0gbGFnKGlzc2l6bGlrJCLEsMWfc2l6bGlrIiwgMiksICAjIExhZyAyCiAgICAgICAgICAgICAgICkKCm11bGFrYXRfbGFnIDwtIG11dGF0ZShtdWxha2F0LAogICAgICAgICAgICAgICBtdWxha2F0X2xhZzEgPSBsYWcobXVsYWthdCQiTcO8bGFrYXQiLCAxKSwgICMgTGFnIDEKICAgICAgICAgICAgICAgbXVsYWthdF9sYWcyID0gbGFnKG11bGFrYXQkIk3DvGxha2F0IiwgMiksICAjIExhZyAyCiAgICAgICAgICAgICAgICkKCmNvbWJpbmVkX2xhZyA8LSBjYmluZChrcmVkaV9sYWcsIGlzX2lsYW5pX2xhZywgaXNzaXpsaWtfbGFnLCBtdWxha2F0X2xhZykKCnQgPC0gdGltZSh1bmVtcGxveW1lbnRfdHMpCnQuYnJlYWsxIDwtIDIwMTgKdC5icmVhazIgPC0gMjAyMQp0YjEgPC0gdHMocG1heCgwLCB0IC0gdC5icmVhazEpLCBzdGFydCA9IDIwMTQsIGVuZCA9IDIwMjQsIGZyZXF1ZW5jeSA9IDEyKQp0YjIgPC0gdHMocG1heCgwLCB0LSB0LmJyZWFrMiksIHN0YXJ0ID0gMjAxNCwgZW5kID0gMjAyNCwgZnJlcXVlbmN5ID0gMTIpCgpmaXQgPC0gdHNsbSh1bmVtcGxveW1lbnRfdHMgfiB0ICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHRiMSArIAogICAgICAgICAgICAgICAgICAgICAgICB0YjIgKyAKICAgICAgICAgICAgICAgICAgICAgICAgc2Vhc29uYWxkdW1teSh1bmVtcGxveW1lbnRfdHMpICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGtyZWRpX3RzICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGlzX2lsYW5pX3RzICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGlzc2l6bGlrX3RzICsgCiAgICAgICAgICAgICAgICAgICAgICAgIG11bGFrYXRfdHMpCgpmaXQubGFnMSA8LSB0c2xtKHVuZW1wbG95bWVudF90cyB+IHQgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdGIxICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHRiMiArIAogICAgICAgICAgICAgICAgICAgICAgICBzZWFzb25hbGR1bW15KHVuZW1wbG95bWVudF90cykgKyAKICAgICAgICAgICAgICAgICAgICAgICAga3JlZGlfbGFnMSArIAogICAgICAgICAgICAgICAgICAgICAgICBpc19pbGFuaV9sYWcxICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGlzc2l6bGlrX2xhZzEgKyAKICAgICAgICAgICAgICAgICAgICAgICAgbXVsYWthdF9sYWcxLCBkYXRhID0gY29tYmluZWRfbGFnKQoKZml0LmxhZzIgPC0gdHNsbSh1bmVtcGxveW1lbnRfdHMgfiB0ICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHRiMSArIAogICAgICAgICAgICAgICAgICAgICAgICB0YjIgKyAKICAgICAgICAgICAgICAgICAgICAgICAgc2Vhc29uYWxkdW1teSh1bmVtcGxveW1lbnRfdHMpICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGtyZWRpX2xhZzIgKyAKICAgICAgICAgICAgICAgICAgICAgICAgaXNfaWxhbmlfbGFnMiArIAogICAgICAgICAgICAgICAgICAgICAgICBpc3Npemxpa19sYWcyICsgCiAgICAgICAgICAgICAgICAgICAgICAgIG11bGFrYXRfbGFnMiwgZGF0YSA9IGNvbWJpbmVkX2xhZykKCm5vX2xhZyA8LSBDVihmaXQpCmxhZ18xIDwtIENWKGZpdC5sYWcxKQpsYWdfMiA8LSBDVihmaXQubGFnMikKQ1ZfZGF0YSA8LSBkYXRhLmZyYW1lKHJiaW5kKG5vX2xhZywgbGFnXzEsIGxhZ18yKSkKQ1ZfZGF0YQpgYGAKCk5vdywgd2Ugd2lsbCBpbnNwZWN0IHRoZSBtb2RlbCBmdXJ0aGVyIGFuZCB0cnkgdG8gcmVtb3ZlIHRoZSB1bm5lY2Vzc2FyeSBwcmVkaWN0b3IuIEluIHRoaXMgY2FzZSBhbGwgb2YgdGhlIHByZWRpY3RvcnMgKGdvb2dsZSB0cmVuZHMgZGF0YSkgYXJlIHJlbW92ZWQgb25lIGJ5IG9uZSBhbmQgdGhlIG1vZGVscyBhcmUgY29tcGFyZWQgYWNjb3JkaW5nIHRvIEFJQyB2YWx1ZXMuIFRoZSBsb3dlcyBBSUMgdmFsdWUgbW9kZWwgaXM6IGZpdC53Lm8ubXVsYWthdC4gVGhpcyBpcyB0aGUgbW9kZWwgdGhhdCBkb2Vzbid0IGNvbnRhaW4gdGhlIGtleXdvcmQgIk3DvGxha2F0Ii4gU28gb3VyIGZpbmFsIG1vZGVsIGlzIGNob3NlbiBhbmQgdGhlIHJlc2lkdWFsIGFuYWx5c2lzIHdpbGwgYmUgcHJvY2VlZGVkIGFjY29yZGluZ2x5LgoKYGBge3J9CmZpdC5ldmVyeXRoaW5nIDwtIHRzbG0odW5lbXBsb3ltZW50X3RzIH4gdCArIAogICAgICAgICAgICAgICAgICAgICAgICB0YjEgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdGIyICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHNlYXNvbmFsZHVtbXkodW5lbXBsb3ltZW50X3RzKSArIAogICAgICAgICAgICAgICAgICAgICAgICBrcmVkaV90cyArIAogICAgICAgICAgICAgICAgICAgICAgICBpc19pbGFuaV90cyArIAogICAgICAgICAgICAgICAgICAgICAgICBpc3Npemxpa190cyArIAogICAgICAgICAgICAgICAgICAgICAgICBtdWxha2F0X3RzKQoKZml0Lncuby5rcmVkaSA8LSB0c2xtKHVuZW1wbG95bWVudF90cyB+IHQgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdGIxICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHRiMiArIAogICAgICAgICAgICAgICAgICAgICAgICBzZWFzb25hbGR1bW15KHVuZW1wbG95bWVudF90cykgKyAKICAgICAgICAgICAgICAgICAgICAgICAgaXNfaWxhbmlfdHMgKyAKICAgICAgICAgICAgICAgICAgICAgICAgaXNzaXpsaWtfdHMgKyAKICAgICAgICAgICAgICAgICAgICAgICAgbXVsYWthdF90cykKCmZpdC53Lm8uaXNfaWxhbmkgPC0gdHNsbSh1bmVtcGxveW1lbnRfdHMgfiB0ICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHRiMSArIAogICAgICAgICAgICAgICAgICAgICAgICB0YjIgKyAKICAgICAgICAgICAgICAgICAgICAgICAgc2Vhc29uYWxkdW1teSh1bmVtcGxveW1lbnRfdHMpICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGtyZWRpX3RzICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGlzc2l6bGlrX3RzICsgCiAgICAgICAgICAgICAgICAgICAgICAgIG11bGFrYXRfdHMpCgpmaXQudy5vLmlzc2l6bGlrIDwtIHRzbG0odW5lbXBsb3ltZW50X3RzIH4gdCArIAogICAgICAgICAgICAgICAgICAgICAgICB0YjEgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdGIyICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHNlYXNvbmFsZHVtbXkodW5lbXBsb3ltZW50X3RzKSArIAogICAgICAgICAgICAgICAgICAgICAgICBrcmVkaV90cyArIAogICAgICAgICAgICAgICAgICAgICAgICBpc19pbGFuaV90cyArIAogICAgICAgICAgICAgICAgICAgICAgICBtdWxha2F0X3RzKQoKZml0Lncuby5tdWxha2F0IDwtIHRzbG0odW5lbXBsb3ltZW50X3RzIH4gdCArIAogICAgICAgICAgICAgICAgICAgICAgICB0YjEgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdGIyICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHNlYXNvbmFsZHVtbXkodW5lbXBsb3ltZW50X3RzKSArIAogICAgICAgICAgICAgICAgICAgICAgICBrcmVkaV90cyArIAogICAgICAgICAgICAgICAgICAgICAgICBpc19pbGFuaV90cyArIAogICAgICAgICAgICAgICAgICAgICAgICBpc3Npemxpa190cykKCmFsbCA8LSBDVihmaXQuZXZlcnl0aGluZykKbm9fa3JlZGkgPC0gQ1YoZml0Lncuby5rcmVkaSkKbm9faXNfaWxhbmkgPC0gQ1YoZml0Lncuby5pc19pbGFuaSkKbm9faXNzaXpsaWsgPC0gQ1YoZml0Lncuby5pc3NpemxpaykKbm9fbXVsYWthdCA8LSBDVihmaXQudy5vLm11bGFrYXQpCkNWX2RhdGEgPC0gZGF0YS5mcmFtZShyYmluZChhbGwsIG5vX2tyZWRpLCBub19pc19pbGFuaSwgbm9zX2lzc2l6bGlrLCBub19tdWxha2F0KSkKQ1ZfZGF0YQpgYGAKClRoZSBtb2RlbCBhbmQgdGhlIGRhdGEgYXJlIHBsb3R0ZWQgaW4gb3JkZXIgdG8gc2VlIHZpc3VhbGx5IGhvdyB0aGV5IGJlaGF2ZS4KCmBgYHtyfQphdXRvcGxvdCh1bmVtcGxveW1lbnRfdHMsIHNlcmllcyA9ICJEYXRhIikgKyAKICBhdXRvbGF5ZXIoZml0dGVkKGZpdC53Lm8ubXVsYWthdCksIHNlcmllcyA9ICJNb2RlbCIpCmBgYAoKRnJvbSB0aGUgcmVzaWR1YWwgYW5hbHlzaXMgcGFydCB3ZSBjYW4gY29uY2x1ZGUgdGhhdDoKCi0gICBUaGUgcmVzaWR1YWxzIHNlZW0gdG8gaGF2ZSBtZWFuIHplcm8gYW5kIHRoZW0gc2VlbSB0byBiZSBub3JtYWxseSBkaXN0cmlidXRlZC4KLSAgIEhvd2V2ZXIgdGhleSBzaG93IGluY3JlYXNpbmcgQUMgZXNwZWNpYWxseSBhdCBsYWdzIDEyLDI0IGFuZCAzNi4gVGhlcmVmb3JlIHdlIGNhbiBkZWR1Y3QgdGhhdCB0aGVyZSBpcyBtb3JlIGluZm9ybWF0aW9uIGxlZnQgb3V0IGVzcGVjaWFsbHkgaW4gc2Vhc29uYWxpdHkgdGVybXMuCgpXaGVuIGNvbnNpZGVyaW5nIGRpZmZlcmVudCBwcmVkaWN0b3JzIHdlIGNhbiBvYnNlcnZlIHRoYXQgSmFudWFyeSwgRmVicnVhcnkgYW5kIE1hcmNoIHNlYXNvbmFsIHZhcmlhYmxlcyBhcmUgYWN0dWFsbHkgbm90IHZlcnkgaW50dWl0aXZlIGFzIHRoZXkgaGF2ZSBoaWdoIHAtdmFsdWVzLgoKV2hlbiB0aGUgUmVzaWR1YWxzIHZzLiBGaXR0ZWQgdmFsdWVzIGdyYXBoIGlzIG9ic2VydmVkLCBpdCBjYW4gYmUgc2VlbiB0aGF0CgpPdmVyYWxsLCB0aGUgbW9kZWwgc2VlbXMgdG8gYmUgYWRlcXVhdGUsIGhvd2V2ZXIgdGhlcmUgYXJlIHBhcnRzIHRvIGltcHJvdmUgdGhlIG1vZGVsLCBlc3BlY2lhbGx5IGluIHNlYXNvbmFsaXR5IHRlcm1zLgoKYGBge3J9CmNoZWNrcmVzaWR1YWxzKGZpdC53Lm8ubXVsYWthdCkKc3VtbWFyeShmaXQudy5vLm11bGFrYXQpCgpyZXNpZHVhbF9maXR0ZWQgPC0gZGF0YS5mcmFtZShjYmluZChGaXR0ZWQgPSBmaXR0ZWQoZml0Lncuby5tdWxha2F0KSwgUmVzaWR1YWxzPXJlc2lkdWFscyhmaXQudy5vLm11bGFrYXQpKSkKZ2dwbG90KHJlc2lkdWFsX2ZpdHRlZCwgYWVzKHggPSBGaXR0ZWQsIHkgPSBSZXNpZHVhbHMpKSArIGdlb21fcG9pbnQoKSArIGdndGl0bGUoIlJlc2lkdWFscyB2cy4gRml0dGVkIFZhbHVlcyIpCmBgYAoKIyMgSG91c2UgUHJpY2UgSW5kZXgKCkluIG9yZGVyIHRvIGdldCBhIG1vcmUgcmVhbCBIb3VzZSBQcmljZSBJbmRleCwgdGhlIGRhdGEgaXMgZGl2aWRlZCB0byBVUyBkb2xsYXIgaW4gb3JkZXIgdG8gZ2V0IHRoZSBxdWFudGl0aWVzIGluIGRvbGxhcnMuCgpTZWFzb25hbGl0eSBjYW4gYmUgb2JzZXJ2ZWQgZXNwZWNpYWxseSBhdCB0aGUgdGltZSBiZXR3ZWVuIDIwMTQgYW5kIDIwMTguCgpUaGVyZSBpcyBhIGNsZWFyIGRvd253YXJkIHRyZW5kIGZyb20gMjAxNCB0byAyMDE4IGFuZCBhbiB1cHdhcmQgdHJlbmQgZnJvbSAyMDIyIHRvIDIwMjQuCgpgYGB7cn0KdGltZV9kYXRhX2hvdXNlIDwtIGMoeWVhcihtaW4oaG91c2VfaW5kZXhfZGF0YSRUYXJpaCkpLCBtb250aChtaW4oaG91c2VfaW5kZXhfZGF0YSRUYXJpaCkpKQoKZG9sbGFyX2RhdGFwYXRoID0gJy9Vc2Vycy9haG1ldGthcmFrb3NlL0Rlc2t0b3AvZG9sYXIueGxzeCcKZG9sbGFyX2RhdGEgPSByZWFkX2V4Y2VsKGRvbGxhcl9kYXRhcGF0aCkKZG9sbGFyX2RhdGEgPC0gZG9sbGFyX2RhdGFbLSgxMjI6MTMzKSxdCmRvbGxhcl9kYXRhIDwtIGRvbGxhcl9kYXRhWywtM10KZG9sbGFyX2RhdGEkIlRQIERLIFVTRCBBIFlUTCIgIDwtIGFzLm51bWVyaWMoZG9sbGFyX2RhdGEkIlRQIERLIFVTRCBBIFlUTCIpCm5hbWVzKGRvbGxhcl9kYXRhKVtuYW1lcyhkb2xsYXJfZGF0YSkgPT0gIlRQIERLIFVTRCBBIFlUTCJdIDwtICJEb2xsYXIiCmRvbGxhcl9kYXRhJFRhcmloIDwtIHBhc3RlKGRvbGxhcl9kYXRhJFRhcmloLCAiLTAxIiwgc2VwID0gIiIpCmRvbGxhcl9kYXRhJFRhcmloIDwtIGFzLkRhdGUoZG9sbGFyX2RhdGEkVGFyaWgpCgpob3VzZV9pbmRleF9kYXRhWywyXSA8LSBob3VzZV9pbmRleF9kYXRhWywyXSAvIGRvbGxhcl9kYXRhWywyXQoKaG91c2VfaW5kZXhfdHMgPC0gdHMoaG91c2VfaW5kZXhfZGF0YSRgSG91c2UgUHJpY2UgSW5kZXhgLCBzdGFydCA9IHRpbWVfZGF0YSwgZnJlcXVlbmN5ID0gMTIpCgphdXRvcGxvdChob3VzZV9pbmRleF90cykgKyBnZ3RpdGxlKCJIb3VzZSBQcmljZSBJbmRleCB2cyBUaW1lIikgKyB4bGFiKCJZZWFyIikgKyB5bGFiKCJIb3VzZSBJbmRleCAyMDE3ID0gMTAwIikKYGBgCgpMZXQncyBsb29rIGF0IHRoZSBhdXRvY29ycmVsYXRpb24gZnVuY3Rpb24gb2YgdGhlIHRpbWUgc2VyaWVzIGluIG9yZGVyIHRvIGNoZWNrIHNlYXNvbmFsaXR5LiBUaGUgQUNGIGRvZXMgbm90IHNob3cgYW55IGNsZWFyIHBhdHRlcm4gb2Ygc2Vhc29uYWxpdHkgaW4gdGhpcyBjYXNlLgoKYGBge3J9CkFjZihob3VzZV9pbmRleF90cywgbGFnLm1heCA9IDI0KQpgYGAKCk5vdywgd2Ugd2FudCB0byBmaW5kIHByZWRpY3RvcnMgZnJvbSBHb29nbGUgVHJlbmRzIHRoYXQgY2FuIGJlIHNvbWVob3cgcmVsYXRlZCB3aXRoIHRoZSBIb3VzZSBQcmljZSBJbmRleCBpbiBUdXJrZXkuIFdoZW4ga2V5d29yZHMgZm9yIHRoaXMgcmVsYXRpb24gaXMgdGhvdWdodCBmb3IsIHRoZXNlIGtleXdvcmRzIGFyZSBmb3VuZCB0byBiZSBsb2dpY2FsIGFuZCByZWxhdGVkIHdpdGggSG91c2UgUHJpY2UgSW5kZXg6CgotICAgIlNhdMSxbMSxayBkYWlyZSI6IE9idmlvdXNseSB0aGlzIGtleXdvcmQgbWF5IGJlIGEgZ29vZCBwcmVkaWN0b3IgZm9yIEhvdXNlIFByaWNlIEluZGV4Ci0gICAiRmFpeiI6IEludGVyZXN0IHJhdGVzIG1heSBpbmNyZWFzZSBjcmVkaXQgcmF0ZXMgZm9yIGhvdXNlcyBhcyB3ZWxsLiBUaGlzIG1heSBoYXZlIGEgcmVsYXRpb24gd2l0aCBIb3VzZSBQcmljZSBJbmRleC4KLSAgICJFbWxhayI6IE9idmlvdXNseSB0aGlzIGtleXdvcmQgbWF5IGJlIGEgZ29vZCBwcmVkaWN0b3IgZm9yIEhvdXNlIFByaWNlIEluZGV4Ci0gICAixLBwb3RlayIKCkl0IHNob3VsZCBiZSBub3RlZCB0aGF0IG1heWJlIHRoZSBsYWdnZWQgdmFsdWVzIG9mIHRoZXNlIGRhdGEgY2FuIGJlIGJldHRlciBwcmVkaWN0b3JzIGJlY2F1c2UsIHBlb3BsZSBtYXkgc2VhcmNoIHRoZXNlIHRlcm1zIGFmdGVyIHRoZSBIb3VzZSBQcmljZSBJbmRleCBpbmNyZWFzZXMuIFRoZXNlIHNlYXJjaCB0ZXJtcyBhcmUgcmVzdWx0cywgc28gdGhlIGFmZmVjdHMgb2YgdGhlc2Ugc2VhcmNoIHRlcm1zIG1heSBiZSBkZWxheWVkLgoKQmVsb3cgYWxsIG9mIHRoZSBkYXRhIGlzIGdhdGhlcmVkIGFuZCB0aW1lIHNlcmllcyBvYmplY3RzIGFyZSBmb3JtZWQuIEFsbCBwb3RlbnRpYWwgcHJlZGljdG9yIGRhdGEgYXJlIHBsb3R0ZWQgYW5kIGEgY29tYmluYXRpb24gb2YgdGhlIHBvdGVudGlhbCBwcmVkaWN0b3JzIGFyZSBjb21iaW5lZC4gVGhlc2UgcHJlZGljdG9ycyBhcmUgYWxzbyBjb21iaW5lZCB3aXRoaW4gYW5vdGhlciBkYXRhIGZyYW1lLgoKYGBge3J9CnNhdGlsaWtfZGFpcmUgPSBmcmVhZCgiL1VzZXJzL2FobWV0a2FyYWtvc2UvRGVza3RvcC9zYXRpbGlrX2RhaXJlLmNzdiIpCm5hbWVzKHNhdGlsaWtfZGFpcmUpW25hbWVzKHNhdGlsaWtfZGFpcmUpID09ICJzYXTEsWzEsWsgZGFpcmU6IChUw7xya2l5ZSkiXSA8LSAiU2F0xLFsxLFrIGRhaXJlIgpzYXRpbGlrX2RhaXJlX3RzIDwtIHRzKHNhdGlsaWtfZGFpcmVbLC0xXSwgc3RhcnQgPSB0aW1lX2RhdGEsIGZyZXF1ZW5jeSA9IDEyKQoKZmFpeiA9IGZyZWFkKCIvVXNlcnMvYWhtZXRrYXJha29zZS9EZXNrdG9wL2ZhaXouY3N2IikKbmFtZXMoZmFpeilbbmFtZXMoZmFpeikgPT0gImZhaXo6IChUw7xya2l5ZSkiXSA8LSAiRmFpeiIKZmFpel90cyA8LSB0cyhmYWl6WywtMV0sIHN0YXJ0ID0gdGltZV9kYXRhLCBmcmVxdWVuY3kgPSAxMikKCmVtbGFrID0gZnJlYWQoIi9Vc2Vycy9haG1ldGthcmFrb3NlL0Rlc2t0b3AvZW1sYWsuY3N2IikKbmFtZXMoZW1sYWspW25hbWVzKGVtbGFrKSA9PSAiZW1sYWs6IChUw7xya2l5ZSkiXSA8LSAiRW1sYWsiCmVtbGFrX3RzIDwtIHRzKGVtbGFrWywtMV0sIHN0YXJ0ID0gdGltZV9kYXRhLCBmcmVxdWVuY3kgPSAxMikKCmlwb3RlayA9IGZyZWFkKCIvVXNlcnMvYWhtZXRrYXJha29zZS9EZXNrdG9wL2lwb3Rlay5jc3YiKQpuYW1lcyhpcG90ZWspW25hbWVzKGlwb3RlaykgPT0gImlwb3RlazogKFTDvHJraXllKSJdIDwtICLEsHBvdGVrIgppcG90ZWtfdHMgPC0gdHMoaXBvdGVrWywtMV0sIHN0YXJ0ID0gdGltZV9kYXRhLCBmcmVxdWVuY3kgPSAxMikKCmF1dG9wbG90KHNhdGlsaWtfZGFpcmVfdHMpCmF1dG9wbG90KGZhaXpfdHMpCmF1dG9wbG90KGVtbGFrX3RzKQphdXRvcGxvdChpcG90ZWtfdHMpCgoKcHJlZGljdG9yc19ocF9pbmRleCA8LSBjYmluZChzYXRpbGlrX2RhaXJlWywtMV0sIGZhaXpbLC0xXSwgZW1sYWtbLC0xXSwgaXBvdGVrWywtMV0pCmRmX2hwX2luZGV4IDwtIGNiaW5kKGhvdXNlX2luZGV4X2RhdGEsIHByZWRpY3RvcnNfaHBfaW5kZXgpCmBgYAoKQmVsb3cgaXMgdGhlIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIGVhY2ggcHJlZGljdG9ycyBhbmQgdGhlIGZvcmVjYXN0IHZhcmlhYmxlLiBUaGUgcmVsYXRpb25zIG9mIGVhY2ggb2YgdGhlbSBjYW4gYmUgb2JzZXJ2ZWQgYmVsb3cuCgpgYGB7cn0KcmVxdWlyZShHR2FsbHkpCmdncGFpcnMoZGZfaHBfaW5kZXhbLC0xXSkKYGBgCgpOb3csIGl0J3MgdGltZSB0byBjcmVhdGUgdGhlIG1vZGVsLiBGaXJzdGx5IHRoZSBsYWdnZWQgZGF0YSBmcmFtZXMgZm9yIGFsbCBvZiB0aGUgc2VsZWN0ZWQgcHJlZGljdG9ycyBhcmUgY3JlYXRlZCAoR29vZ2xlIHRyZW5kcyBkYXRhKS4gVGhpcyBpcyB0byBjb21wYXJlIHRoZSBsYWdnZWQgbW9kZWxzIHdpdGhvdXQgdGhlIGxhZ2dlZCBtb2RlbC4gVGhlbiB0aGUgcGllY2Ugd2lzZSBsaW5lYXIgdHJlbmQgaXMgZm9ybWVkLiBUaHJlZSBwb3NzaWJsZSBtb2RlbHMgYXJlIGNyZWF0ZWQ6CgotICAgZml0OiBVc2luZyBhbGwgdGhlIHByZWRpY3RvcnMKLSAgIGZpdC5sYWcxOiBVc2luZyBhbGwgdGhlIGxhZy0xIHByZWRpY3RvcnMKLSAgIGZpdC5sYWcyOiBVc2luZyBhbGwgdGhlIGxhZy0yIHByZWRpY3RvcnMKClRoZSBiZXN0IG9uZSB3aWxsIGJlIGV2YWx1YXRlZCBiYXNlZCBvbiB0aGUgbG93ZXN0IEFJQyB2YWx1ZS4gQXMgaXQgY2FuIGJlIHNlZW4gYmVsb3csIHRoZSBsb3dlc3QgQUlDIHZhbHVlIGlzIHRoZSBvbmUgd2l0aCBsYWctMS4gV2Ugd2lsbCBwcm9jZWVkIHdpdGggdGhpcyBtb2RlbCBpbiB0aGUgdXBjb21pbmcgY29tcGFyaXNvbnMuCgpgYGB7cn0KCmxpYnJhcnkoZHBseXIpCnNhdGlsaWtfZGFpcmVfbGFnIDwtIG11dGF0ZShzYXRpbGlrX2RhaXJlLAogICAgICAgICAgICAgICBzYXRpbGlrX2RhaXJlX2xhZzEgPSBsYWcoc2F0aWxpa19kYWlyZSRgU2F0xLFsxLFrIGRhaXJlYCwgMSksICAjIExhZyAxCiAgICAgICAgICAgICAgIHNhdGlsaWtfZGFpcmVfbGFnMiA9IGxhZyhzYXRpbGlrX2RhaXJlJGBTYXTEsWzEsWsgZGFpcmVgLCAyKSwgICMgTGFnIDIKICAgICAgICAgICAgICAgKQoKZmFpel9sYWcgPC0gbXV0YXRlKGZhaXosCiAgICAgICAgICAgICAgIGZhaXpfbGFnMSA9IGxhZyhmYWl6JEZhaXosIDEpLCAgIyBMYWcgMQogICAgICAgICAgICAgICBmYWl6X2xhZzIgPSBsYWcoZmFpeiRGYWl6LCAyKSwgICMgTGFnIDIKICAgICAgICAgICAgICAgKQoKZW1sYWtfbGFnIDwtIG11dGF0ZShlbWxhaywKICAgICAgICAgICAgICAgZW1sYWtfbGFnMSA9IGxhZyhlbWxhayRFbWxhaywgMSksICAjIExhZyAxCiAgICAgICAgICAgICAgIGVtbGFrX2xhZzIgPSBsYWcoZW1sYWskRW1sYWssIDIpLCAgIyBMYWcgMgogICAgICAgICAgICAgICApCgppcG90ZWtfbGFnIDwtIG11dGF0ZShpcG90ZWssCiAgICAgICAgICAgICAgIGlwb3Rla19sYWcxID0gbGFnKGlwb3RlayTEsHBvdGVrLCAxKSwgICMgTGFnIDEKICAgICAgICAgICAgICAgaXBvdGVrX2xhZzIgPSBsYWcoaXBvdGVrJMSwcG90ZWssIDIpLCAgIyBMYWcgMgogICAgICAgICAgICAgICApCgpjb21iaW5lZF9sYWcgPC0gY2JpbmQoc2F0aWxpa19kYWlyZV9sYWcsIGZhaXpfbGFnLCBlbWxha19sYWcsIGlwb3Rla19sYWcpCgp0IDwtIHRpbWUodW5lbXBsb3ltZW50X3RzKQp0LmJyZWFrMSA8LSAyMDE4CnQuYnJlYWsyIDwtIDIwMjIKdGIxIDwtIHRzKHBtYXgoMCwgdCAtIHQuYnJlYWsxKSwgc3RhcnQgPSAyMDE0LCBlbmQgPSAyMDI0LCBmcmVxdWVuY3kgPSAxMikKdGIyIDwtIHRzKHBtYXgoMCwgdC0gdC5icmVhazIpLCBzdGFydCA9IDIwMTQsIGVuZCA9IDIwMjQsIGZyZXF1ZW5jeSA9IDEyKQoKZml0IDwtIHRzbG0oaG91c2VfaW5kZXhfdHMgfiBzYXRpbGlrX2RhaXJlX3RzICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGZhaXpfdHMrIAogICAgICAgICAgICAgICAgICAgICAgICBlbWxha190cyArCiAgICAgICAgICAgICAgICAgICAgICAgIGlwb3Rla190cyArIAogICAgICAgICAgICAgICAgICAgICAgICB0ICsKICAgICAgICAgICAgICAgICAgICAgICAgdGIxICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHRiMikKCmZpdC5sYWcxIDwtIHRzbG0oaG91c2VfaW5kZXhfdHMgfiB0ICsKICAgICAgICAgICAgICAgICAgICAgICAgdGIxICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHRiMiArIAogICAgICAgICAgICAgICAgICAgICAgICBzYXRpbGlrX2RhaXJlX2xhZzEgKyAKICAgICAgICAgICAgICAgICAgICAgICAgZmFpel9sYWcxICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGVtbGFrX2xhZzEgKwogICAgICAgICAgICAgICAgICAgICAgICBpcG90ZWtfbGFnMSwgZGF0YSA9IGNvbWJpbmVkX2xhZykKCmZpdC5sYWcyIDwtIHRzbG0oaG91c2VfaW5kZXhfdHMgfiB0ICsKICAgICAgICAgICAgICAgICAgICAgICAgdGIxICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHRiMiArIAogICAgICAgICAgICAgICAgICAgICAgICBzYXRpbGlrX2RhaXJlX2xhZzIgKyAKICAgICAgICAgICAgICAgICAgICAgICAgZmFpel9sYWcyICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGVtbGFrX2xhZzIgKwogICAgICAgICAgICAgICAgICAgICAgICBpcG90ZWtfbGFnMiwgZGF0YSA9IGNvbWJpbmVkX2xhZykgCgoKbm9fbGFnIDwtIENWKGZpdCkKbGFnXzEgPC0gQ1YoZml0LmxhZzEpCmxhZ18yIDwtIENWKGZpdC5sYWcyKQpDVl9kYXRhIDwtIGRhdGEuZnJhbWUocmJpbmQobm9fbGFnLCBsYWdfMSwgbGFnXzIpKQpDVl9kYXRhCmBgYAoKTm93LCB3ZSB3aWxsIGluc3BlY3QgdGhlIG1vZGVsIGZ1cnRoZXIgYW5kIHRyeSB0byByZW1vdmUgdGhlIHVubmVjZXNzYXJ5IHByZWRpY3Rvci4gSW4gdGhpcyBjYXNlIGFsbCBvZiB0aGUgcHJlZGljdG9ycyAoR29vZ2xlIHRyZW5kcyBkYXRhKSBhcmUgcmVtb3ZlZCBvbmUgYnkgb25lIGFuZCB0aGUgbW9kZWxzIGFyZSBjb21wYXJlZCBhY2NvcmRpbmcgdG8gQUlDIHZhbHVlcy4gVGhlIGxvd2VzdCBBSUMgdmFsdWUgbW9kZWwgaXM6IGZpdC53Lm8uZW1sYWsuIFRoaXMgaXMgdGhlIG1vZGVsIHRoYXQgZG9lc24ndCBjb250YWluIHRoZSBrZXl3b3JkICJFbWxhayIuIFNvIG91ciBmaW5hbCBtb2RlbCBpcyBjaG9zZW4gYW5kIHRoZSByZXNpZHVhbCBhbmFseXNpcyB3aWxsIGJlIHByb2NlZWRlZCBhY2NvcmRpbmdseS4KCmBgYHtyfQpmaXQuZXZlcnl0aGluZyA8LSB0c2xtKGhvdXNlX2luZGV4X3RzIH4gdCArCiAgICAgICAgICAgICAgICAgICAgICAgIHRiMSArIAogICAgICAgICAgICAgICAgICAgICAgICB0YjIgKyAKICAgICAgICAgICAgICAgICAgICAgICAgc2F0aWxpa19kYWlyZV9sYWcxICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGZhaXpfbGFnMSArIAogICAgICAgICAgICAgICAgICAgICAgICBlbWxha19sYWcxICsKICAgICAgICAgICAgICAgICAgICAgICAgaXBvdGVrX2xhZzEsIGRhdGEgPSBjb21iaW5lZF9sYWcpCgpmaXQudy5vLnNhdGlsaWtfZGFpcmUgPC0gdHNsbShob3VzZV9pbmRleF90cyB+IHQgKwogICAgICAgICAgICAgICAgICAgICAgICB0YjEgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdGIyICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGZhaXpfbGFnMSArIAogICAgICAgICAgICAgICAgICAgICAgICBlbWxha19sYWcxICsKICAgICAgICAgICAgICAgICAgICAgICAgaXBvdGVrX2xhZzEsIGRhdGEgPSBjb21iaW5lZF9sYWcpCgpmaXQudy5vLmZhaXogPC0gdHNsbShob3VzZV9pbmRleF90cyB+IHQgKwogICAgICAgICAgICAgICAgICAgICAgICB0YjEgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdGIyICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHNhdGlsaWtfZGFpcmVfbGFnMSArIAogICAgICAgICAgICAgICAgICAgICAgICBlbWxha19sYWcxICsKICAgICAgICAgICAgICAgICAgICAgICAgaXBvdGVrX2xhZzEsIGRhdGEgPSBjb21iaW5lZF9sYWcpCgpmaXQudy5vLmVtbGFrIDwtIHRzbG0oaG91c2VfaW5kZXhfdHMgfiB0ICsKICAgICAgICAgICAgICAgICAgICAgICAgdGIxICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHRiMiArIAogICAgICAgICAgICAgICAgICAgICAgICBzYXRpbGlrX2RhaXJlX2xhZzEgKyAKICAgICAgICAgICAgICAgICAgICAgICAgZmFpel9sYWcxICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGlwb3Rla19sYWcxLCBkYXRhID0gY29tYmluZWRfbGFnKQoKZml0Lncuby5pcG90ZWsgPC0gdHNsbShob3VzZV9pbmRleF90cyB+IHQgKwogICAgICAgICAgICAgICAgICAgICAgICB0YjEgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdGIyICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHNhdGlsaWtfZGFpcmVfbGFnMSArIAogICAgICAgICAgICAgICAgICAgICAgICBmYWl6X2xhZzEgKyAKICAgICAgICAgICAgICAgICAgICAgICAgZW1sYWtfbGFnMSwgZGF0YSA9IGNvbWJpbmVkX2xhZykKCmFsbCA8LSBDVihmaXQuZXZlcnl0aGluZykKbm9fc2F0aWxpa19kYWlyZSA8LSBDVihmaXQudy5vLnNhdGlsaWtfZGFpcmUpCm5vX2ZhaXogPC0gQ1YoZml0Lncuby5mYWl6KQpub19lbWxhayA8LSBDVihmaXQudy5vLmVtbGFrKQpub19pcG90ZWsgPC0gQ1YoZml0Lncuby5pcG90ZWspCkNWX2RhdGEgPC0gZGF0YS5mcmFtZShyYmluZChhbGwsIG5vX3NhdGlsaWtfZGFpcmUsIG5vX2ZhaXosIG5vX2VtbGFrLCBub19pcG90ZWspKQpDVl9kYXRhCmBgYApUaGUgbW9kZWwgYW5kIHRoZSBkYXRhIGFyZSBwbG90dGVkIGluIG9yZGVyIHRvIHNlZSB2aXN1YWxseSBob3cgdGhleSBiZWhhdmUuCgpgYGB7cn0KYXV0b3Bsb3QoaG91c2VfaW5kZXhfdHMsIHNlcmllcyA9ICJEYXRhIikgKyAKICBhdXRvbGF5ZXIoZml0dGVkKGZpdC53Lm8uZW1sYWspLCBzZXJpZXMgPSAiTW9kZWwiKQpgYGAKRnJvbSB0aGUgcmVzaWR1YWwgYW5hbHlzaXMgcGFydCB3ZSBjYW4gY29uY2x1ZGUgdGhhdDoKCi0gICBUaGUgcmVzaWR1YWxzIHNlZW0gdG8gaGF2ZSBtZWFuIHplcm8gYW5kIHRoZW0gc2VlbSB0byBiZSBub3JtYWxseSBkaXN0cmlidXRlZC4KLSAgIEhvd2V2ZXIgdGhleSBzaG93IGluY3JlYXNpbmcgQUMgZXNwZWNpYWxseSBhdCBsYWdzIDEsMiwxMiwxOCwzMC4gVGhlcmVmb3JlIHdlIGNhbiBkZWR1Y3QgdGhhdCB0aGVyZSBpcyBtb3JlIGluZm9ybWF0aW9uIGxlZnQgb3V0LgoKV2hlbiBjb25zaWRlcmluZyBkaWZmZXJlbnQgcHJlZGljdG9ycyB3ZSBjYW4gb2JzZXJ2ZSB0aGF0IHRiMSB2YXJpYWJsZSBpcyBhY3R1YWxseSBub3QgdmVyeSBpbnR1aXRpdmUgYXMgaXQgaGFzIGEgdmVyeSBoaWdoIHAtdmFsdWUuCgpXaGVuIHRoZSBSZXNpZHVhbHMgdnMuIEZpdHRlZCB2YWx1ZXMgZ3JhcGggaXMgb2JzZXJ2ZWQsIGl0IGNhbiBiZSBzZWVuIHRoYXQgdGhlIHJlc2lkdWFscyBhcmUga2luZCBvZiBzY2F0dGVyZWQgYXJvdW5kIAoKT3ZlcmFsbCwgdGhlIG1vZGVsIHNlZW1zIHRvIGJlIGFkZXF1YXRlLCBob3dldmVyIHRoZXJlIGFyZSBwYXJ0cyB0byBpbXByb3ZlIHRoZSBtb2RlbCwgZXNwZWNpYWxseSBpbiB0cmVuZCB0ZXJtcy4KCmBgYHtyfQpzdW1tYXJ5KGZpdC53Lm8uZW1sYWspCmNoZWNrcmVzaWR1YWxzKGZpdC53Lm8uZW1sYWspCgpyZXNpZHVhbF9maXR0ZWQgPC0gZGF0YS5mcmFtZShjYmluZChGaXR0ZWQgPSBmaXR0ZWQoZml0Lncuby5lbWxhayksIFJlc2lkdWFscz1yZXNpZHVhbHMoZml0Lncuby5lbWxhaykpKQpnZ3Bsb3QocmVzaWR1YWxfZml0dGVkLCBhZXMoeCA9IEZpdHRlZCwgeSA9IFJlc2lkdWFscykpICsgZ2VvbV9wb2ludCgpICsgZ2d0aXRsZSgiUmVzaWR1YWxzIHZzLiBGaXR0ZWQgVmFsdWVzIikKYGBgCiMjIFJlYWwgU2VjdG9yIENvbmZpZGVuY2UKCkxhc3RseSwgdGhlIHJlZ3Jlc3Npb24gbW9kZWwgZm9yIHRoZSBSZWFsIFNlY3RvciBDb25maWRlbmNlIGRhdGEgd2lsbCBiZSBidWlsdC4KCkJlbG93IGlzIHRoZSBSZWFsIFNlY3RvciBDb25maWRlbmNlIHZzLiBUaW1lIGdyYXBoLiBXZSBjYW4gbWFrZSBzb21lIGRlZHVjdGlvbnMgb3V0IG9mIGl0OgoKLSAgIFRoZXJlIHNlZW1zIHRvIGJlIHNlYXNvbmFsaXR5IGVzcGVjaWFsbHkgYmV0d2VlbiAyMDE0LTIwMTguCi0gICBUaGVyZSBzZWVtcyB0byBiZSBubyB0cmVuZAotICAgVGhlcmUgaXMgYSBzaGFycCBkZWNyZWFzZSBpbiAyMDIwIE1hcmNoLCBtb3N0IHByb2JhYmx5IGR1ZSB0byB0aGUgY29yb25hLXZpcnVzLgoKYGBge3J9CmNvbmZpZGVuY2VfdHMgPC0gdHMoY29uZmlkZW5jZSQiUmVhbCBTZWN0b3IgQ29uZmlkZW5jZSBJbmRleCIsIHN0YXJ0ID0gdGltZV9kYXRhLCBmcmVxdWVuY3kgPSAxMikKZGF0YS5mcmFtZShjb25maWRlbmNlX3RzKQoKYXV0b3Bsb3QoY29uZmlkZW5jZV90cykgKyBnZ3RpdGxlKCJSZWFsIFNlY3RvciBDb25maWRlbmNlIHZzIFRpbWUiKSArIHhsYWIoIlllYXIiKSArIHlsYWIoIkNvbmZpZGVuY2UiKQpgYGAKTGV0J3MgbG9vayBhdCB0aGUgYXV0b2NvcnJlbGF0aW9uIGZ1bmN0aW9uIG9mIHRoZSB0aW1lIHNlcmllcyBpbiBvcmRlciB0byBjaGVjayBzZWFzb25hbGl0eS4gVGhlIEFDRiBkb2VzIG5vdCBzaG93IGFueSBjbGVhciBwYXR0ZXJuIG9mIHNlYXNvbmFsaXR5IGluIHRoaXMgY2FzZS4KCmBgYHtyfQpnZ0FjZihjb25maWRlbmNlX3RzLCBsYWcubWF4ID0gNDgpCmBgYApOb3csIHdlIHdhbnQgdG8gZmluZCBwcmVkaWN0b3JzIGZyb20gR29vZ2xlIFRyZW5kcyB0aGF0IGNhbiBiZSBzb21laG93IHJlbGF0ZWQgd2l0aCB0aGUgUmVhbCBTZWN0b3IgQ29uZmlkZW5jZSBpbiBUdXJrZXkuIFdoZW4ga2V5d29yZHMgZm9yIHRoaXMgcmVsYXRpb24gaXMgdGhvdWdodCBmb3IsIHRoZXNlIGtleXdvcmRzIGFyZSBmb3VuZCB0byBiZSBsb2dpY2FsIGFuZCByZWxhdGVkIHdpdGggUmVhbCBTZWN0b3IgQ29uZmlkZW5jZQoKLSAgICJGYWl6IjogSW5jcmVhc2UgaW4gaW50ZXJlc3QgcmF0ZXMgbWF5IGJlIGEgYmFkIHNpZ24gZm9yIGNvbmZpZGVuY2UKLSAgICJUaWNhcmV0IjogSW5jcmVhc2UgaW4gdHJhZGUgbWF5IG1lYW4gbW9yZSBjb25maWRlbmNlCi0gICAiVXJldGltIjogSW5jcmVhc2UgaW4gcHJvZHVjdGlvbiBtYXkgbWVhbiBtb3JlIGNvbmZpZGVuY2UKLSAgICLEsHN0aWhkYW0iOiBJbmNyZWFzZSBpbiBlbXBsb3ltZW50IG1heSBtZWFuIG1vcmUgY29uZmlkZW5jZQoKSXQgc2hvdWxkIGJlIG5vdGVkIHRoYXQgbWF5YmUgdGhlIGxhZ2dlZCB2YWx1ZXMgb2YgdGhlc2UgZGF0YSBjYW4gYmUgYmV0dGVyIHByZWRpY3RvcnMgYmVjYXVzZSwgcGVvcGxlIG1heSBzZWFyY2ggdGhlc2UgdGVybXMgYWZ0ZXIgdGhlIFJlYWwgU2VjdG9yIENvbmZpZGVuY2UgY2hhbmdlcyBUaGVzZSBzZWFyY2ggdGVybXMgYXJlIHJlc3VsdHMsIHNvIHRoZSBhZmZlY3RzIG9mIHRoZXNlIHNlYXJjaCB0ZXJtcyBtYXkgYmUgZGVsYXllZC4KCkJlbG93IGFsbCBvZiB0aGUgZGF0YSBpcyBnYXRoZXJlZCBhbmQgdGltZSBzZXJpZXMgb2JqZWN0cyBhcmUgZm9ybWVkLiBBbGwgcG90ZW50aWFsIHByZWRpY3RvciBkYXRhIGFyZSBwbG90dGVkIGFuZCBhIGNvbWJpbmF0aW9uIG9mIHRoZSBwb3RlbnRpYWwgcHJlZGljdG9ycyBhcmUgY29tYmluZWQuIFRoZXNlIHByZWRpY3RvcnMgYXJlIGFsc28gY29tYmluZWQgd2l0aGluIGFub3RoZXIgZGF0YSBmcmFtZS4KCkFsc28gYSB0aW1lIHNlcmllcyBmb3IgY29yb25hLXN0YXJ0IGR1bW15IHZhcmlhYmxlIGlzIGNyZWF0ZWQKCmBgYHtyfQp0aWNhcmV0ID0gZnJlYWQoIi9Vc2Vycy9haG1ldGthcmFrb3NlL0Rlc2t0b3AvdGljYXJldC5jc3YiKQpuYW1lcyh0aWNhcmV0KVtuYW1lcyh0aWNhcmV0KSA9PSAidGljYXJldDogKFTDvHJraXllKSJdIDwtICJUaWNhcmV0Igp0aWNhcmV0X3RzIDwtIHRzKHRpY2FyZXRbLC0xXSwgc3RhcnQgPSB0aW1lX2RhdGEsIGZyZXF1ZW5jeSA9IDEyKQoKdXJldGltID0gZnJlYWQoIi9Vc2Vycy9haG1ldGthcmFrb3NlL0Rlc2t0b3AvdXJldGltLmNzdiIpCm5hbWVzKHVyZXRpbSlbbmFtZXModXJldGltKSA9PSAiw7xyZXRpbTogKFTDvHJraXllKSJdIDwtICLDnHJldGltIgp1cmV0aW1fdHMgPC0gdHModXJldGltWywtMV0sIHN0YXJ0ID0gdGltZV9kYXRhLCBmcmVxdWVuY3kgPSAxMikKCmlzdGloZGFtID0gZnJlYWQoIi9Vc2Vycy9haG1ldGthcmFrb3NlL0Rlc2t0b3AvaXN0aWhkYW0uY3N2IikKbmFtZXMoaXN0aWhkYW0pW25hbWVzKGlzdGloZGFtKSA9PSAiaXN0aWhkYW06IChUw7xya2l5ZSkiXSA8LSAixLBzdGloZGFtIgppc3RpaGRhbV90cyA8LSB0cyhpc3RpaGRhbVssLTFdLCBzdGFydCA9IHRpbWVfZGF0YSwgZnJlcXVlbmN5ID0gMTIpCgpjb3JvbmFfdmFsdWVzIDwtIHJlcCgwLCAxMjEpCmNvcm9uYV92YWx1ZXNbNzVdIDwtIDEKY29yb25hX3RzIDwtIHRzKGNvcm9uYV92YWx1ZXMsIHN0YXJ0ID0gYygyMDE0LCAxKSwgZnJlcXVlbmN5ID0gMTIpCgphdXRvcGxvdChmYWl6X3RzKQphdXRvcGxvdCh0aWNhcmV0X3RzKQphdXRvcGxvdCh1cmV0aW1fdHMpCmF1dG9wbG90KGlzdGloZGFtX3RzKQphdXRvcGxvdChjb3JvbmFfdHMpCgpwcmVkaWN0b3JzX2NvbmZpZGVuY2UgPC0gY2JpbmQoZmFpelssLTFdLCB0aWNhcmV0WywtMV0sIHVyZXRpbVssLTFdLCBpc3RpaGRhbVssLTFdKQpkZl9jb25maWRlbmNlIDwtIGNiaW5kKGNvbmZpZGVuY2UsIHByZWRpY3RvcnNfY29uZmlkZW5jZSkKCmBgYApCZWxvdyBpcyB0aGUgY29ycmVsYXRpb25zIGJldHdlZW4gZWFjaCBwcmVkaWN0b3JzIGFuZCB0aGUgZm9yZWNhc3QgdmFyaWFibGUuIFRoZSByZWxhdGlvbnMgb2YgZWFjaCBvZiB0aGVtIGNhbiBiZSBvYnNlcnZlZCBiZWxvdy4KYGBge3J9CnJlcXVpcmUoR0dhbGx5KQpnZ3BhaXJzKGRmX2NvbmZpZGVuY2VbLC0xXSkKYGBgCgpXZSB3ZXJlIG5vdCBhYmxlIHRvIGRlY2lkZSB3aGV0aGVyIHNlYXNuYWxpdHkgYW5kIHRyZW5kIHdlcmUgbmVjZXNzYXJ5LiBBcHBhcmVudGx5IHRoZSBhZGp1c3RlZCBSXjIgdmFsdWUgdGVsbHMgdXMgdG8gYWRkIHNlYXNub2FsaXR5IGFuZCB0cmVuZCBhcyBwcmVkaWN0b3JzCmBgYHtyfQpmaXQgPC0gdHNsbShjb25maWRlbmNlX3RzIH4gZmFpel90cyArIAogICAgICAgICAgICAgICAgICAgICAgICB0aWNhcmV0X3RzICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHVyZXRpbV90cyArIAogICAgICAgICAgICAgICAgICAgICAgICBpc3RpaGRhbV90cyArIAogICAgICAgICAgICAgICAgICAgICAgICBjb3JvbmFfdHMgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdCArIAogICAgICAgICAgICAgICAgICAgICAgICBzZWFzb24pCgpmaXQuc2Vhc29uIDwtIHRzbG0oY29uZmlkZW5jZV90cyB+IGZhaXpfdHMgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdGljYXJldF90cyArIAogICAgICAgICAgICAgICAgICAgICAgICB1cmV0aW1fdHMgKyAKICAgICAgICAgICAgICAgICAgICAgICAgaXN0aWhkYW1fdHMgKyAKICAgICAgICAgICAgICAgICAgICAgICAgY29yb25hX3RzICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHNlYXNvbikKCmZpdC50cmVuZCA8LSB0c2xtKGNvbmZpZGVuY2VfdHMgfiBmYWl6X3RzICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2FyZXRfdHMgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdXJldGltX3RzICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGlzdGloZGFtX3RzICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGNvcm9uYV90cyArIAogICAgICAgICAgICAgICAgICAgICAgICB0KQpmaXQubm9uZSA8LSB0c2xtKGNvbmZpZGVuY2VfdHMgfiBmYWl6X3RzICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2FyZXRfdHMgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdXJldGltX3RzICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGlzdGloZGFtX3RzICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGNvcm9uYV90cykKCm5vX3NlYXNvbl9ub190cmVuZCA8LSBDVihmaXQudHJlbmQpCnNlYXNvbl9ub190cmVuZCA8LSBDVihmaXQuc2Vhc29uKQp0cmVuZF9ub19zZWFzb24gPC0gQ1YoZml0LnRyZW5kKQphbGwgPC0gQ1YoZml0KQpDVl9kYXRhIDwtIGRhdGEuZnJhbWUocmJpbmQobm9fc2Vhc29uX25vX3RyZW5kLCBzZWFzb25fbm9fdHJlbmQsIHRyZW5kX25vX3NlYXNvbiwgYWxsKSkKQ1ZfZGF0YQpgYGAKTm93aSB0aGUgbGFnZ2VkIGRhdGEgZnJhbWVzIGZvciBhbGwgb2YgdGhlIHNlbGVjdGVkIHByZWRpY3RvcnMgYXJlIGNyZWF0ZWQgKEdvb2dsZSB0cmVuZHMgZGF0YSkuIFRoaXMgaXMgdG8gY29tcGFyZSB0aGUgbGFnZ2VkIG1vZGVscyB3aXRob3V0IHRoZSBsYWdnZWQgbW9kZWwuIFRoZW4gdGhlIHBpZWNlIHdpc2UgbGluZWFyIHRyZW5kIGlzIGZvcm1lZC4gVGhyZWUgcG9zc2libGUgbW9kZWxzIGFyZSBjcmVhdGVkOgoKLSAgIGZpdDogVXNpbmcgYWxsIHRoZSBwcmVkaWN0b3JzCi0gICBmaXQubGFnMTogVXNpbmcgYWxsIHRoZSBsYWctMSBwcmVkaWN0b3JzCi0gICBmaXQubGFnMjogVXNpbmcgYWxsIHRoZSBsYWctMiBwcmVkaWN0b3JzCgpUaGUgYmVzdCBvbmUgd2lsbCBiZSBldmFsdWF0ZWQgYmFzZWQgb24gdGhlIGxvd2VzdCBBSUMgdmFsdWUuIEFzIGl0IGNhbiBiZSBzZWVuIGJlbG93LCB0aGUgbG93ZXN0IEFJQyB2YWx1ZSBpcyB0aGUgb25lIHdpdGggbm8gbGFnLiBXZSB3aWxsIHByb2NlZWQgd2l0aCB0aGlzIG1vZGVsIGluIHRoZSB1cGNvbWluZyBjb21wYXJpc29ucy4KYGBge3J9CmxpYnJhcnkoZHBseXIpCgpmYWl6X2xhZyA8LSBtdXRhdGUoZmFpeiwKICAgICAgICAgICAgICAgZmFpel9sYWcxID0gbGFnKGZhaXokRmFpeiwgMSksICAjIExhZyAxCiAgICAgICAgICAgICAgIGZhaXpfbGFnMiA9IGxhZyhmYWl6JEZhaXosIDIpLCAgIyBMYWcgMgogICAgICAgICAgICAgICApCgp0aWNhcmV0X2xhZyA8LSBtdXRhdGUodGljYXJldCwKICAgICAgICAgICAgICAgdGljYXJldF9sYWcxID0gbGFnKHRpY2FyZXQkVGljYXJldCwgMSksICAjIExhZyAxCiAgICAgICAgICAgICAgIHRpY2FyZXRfbGFnMiA9IGxhZyh0aWNhcmV0JFRpY2FyZXQsIDIpLCAgIyBMYWcgMgogICAgICAgICAgICAgICApCgp1cmV0aW1fbGFnIDwtIG11dGF0ZSh1cmV0aW0sCiAgICAgICAgICAgICAgIHVyZXRpbV9sYWcxID0gbGFnKHVyZXRpbSTDnHJldGltLCAxKSwgICMgTGFnIDEKICAgICAgICAgICAgICAgdXJldGltX2xhZzIgPSBsYWcodXJldGltJMOccmV0aW0sIDIpLCAgIyBMYWcgMgogICAgICAgICAgICAgICApCgppc3RpaGRhbV9sYWcgPC0gbXV0YXRlKGlzdGloZGFtLAogICAgICAgICAgICAgICBpc3RpaGRhbV9sYWcxID0gbGFnKGlzdGloZGFtJMSwc3RpaGRhbSwgMSksICAjIExhZyAxCiAgICAgICAgICAgICAgIGlzdGloZGFtX2xhZzIgPSBsYWcoaXN0aWhkYW0kxLBzdGloZGFtLCAyKSwgICMgTGFnIDIKICAgICAgICAgICAgICAgKQoKY29tYmluZWRfbGFnIDwtIGNiaW5kKGZhaXpfbGFnLCB0aWNhcmV0X2xhZywgdXJldGltX2xhZywgaXN0aWhkYW1fbGFnKQoKZml0IDwtIHRzbG0oY29uZmlkZW5jZV90cyB+IGZhaXpfdHMgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdGljYXJldF90cyArIAogICAgICAgICAgICAgICAgICAgICAgICB1cmV0aW1fdHMgKyAKICAgICAgICAgICAgICAgICAgICAgICAgaXN0aWhkYW1fdHMgKyAKICAgICAgICAgICAgICAgICAgICAgICAgY29yb25hX3RzICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHQgKyAKICAgICAgICAgICAgICAgICAgICAgICAgc2Vhc29uKQoKZml0LmxhZzEgPC0gdHNsbShjb25maWRlbmNlX3RzIH4gdCArIAogICAgICAgICAgICAgICAgICAgICAgICBzZWFzb24gKyAKICAgICAgICAgICAgICAgICAgICAgICAgZmFpel9sYWcxICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2FyZXRfbGFnMSArIAogICAgICAgICAgICAgICAgICAgICAgICB1cmV0aW1fbGFnMSArIAogICAgICAgICAgICAgICAgICAgICAgICBpc3RpaGRhbV9sYWcxLCBkYXRhID0gY29tYmluZWRfbGFnKQoKZml0LmxhZzIgPC0gdHNsbShjb25maWRlbmNlX3RzIH4gdCArIAogICAgICAgICAgICAgICAgICAgICAgICBzZWFzb24gKyAKICAgICAgICAgICAgICAgICAgICAgICAgZmFpel9sYWcyICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2FyZXRfbGFnMiArIAogICAgICAgICAgICAgICAgICAgICAgICB1cmV0aW1fbGFnMiArIAogICAgICAgICAgICAgICAgICAgICAgICBpc3RpaGRhbV9sYWcyLCBkYXRhID0gY29tYmluZWRfbGFnKQoKbm9fbGFnIDwtIENWKGZpdCkKbGFnXzEgPC0gQ1YoZml0LmxhZzEpCmxhZ18yIDwtIENWKGZpdC5sYWcyKQpDVl9kYXRhIDwtIGRhdGEuZnJhbWUocmJpbmQobm9fbGFnLCBsYWdfMSwgbGFnXzIpKQpDVl9kYXRhCmBgYApOb3csIHdlIHdpbGwgaW5zcGVjdCB0aGUgbW9kZWwgZnVydGhlciBhbmQgdHJ5IHRvIHJlbW92ZSB0aGUgdW5uZWNlc3NhcnkgcHJlZGljdG9yLiBJbiB0aGlzIGNhc2UgYWxsIG9mIHRoZSBwcmVkaWN0b3JzIChHb29nbGUgdHJlbmRzIGRhdGEpIGFyZSByZW1vdmVkIG9uZSBieSBvbmUgYW5kIHRoZSBtb2RlbHMgYXJlIGNvbXBhcmVkIGFjY29yZGluZyB0byBBSUMgYW5kIGFkai4gUl4yIHZhbHVlcy4gVGhlIGJlc3QgbW9kZWxzIGFyZSBmaXQuZXZlcnl0aGluZyBhbmQgZml0Lncuby5jb3JvbmEgcmVzcGVjdGl2ZWx5IGZvciBhZGouIFJeMiB2YWx1ZSBhbmQgQUlDIHZhbHVlLiBXZSB3aWxsIHByb2NlZWQgd2l0aCBmaXQuZXZlcnl0aGluZwpgYGB7cn0KZml0LmV2ZXJ5dGhpbmcgPC0gdHNsbShjb25maWRlbmNlX3RzIH4gZmFpel90cyArIAogICAgICAgICAgICAgICAgICAgICAgICB0aWNhcmV0X3RzICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHVyZXRpbV90cyArIAogICAgICAgICAgICAgICAgICAgICAgICBpc3RpaGRhbV90cyArIAogICAgICAgICAgICAgICAgICAgICAgICBjb3JvbmFfdHMgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdCArIAogICAgICAgICAgICAgICAgICAgICAgICBzZWFzb24pCgpmaXQudy5vLmZhaXogPC0gdHNsbShjb25maWRlbmNlX3RzIH4gdGljYXJldF90cyArIAogICAgICAgICAgICAgICAgICAgICAgICB1cmV0aW1fdHMgKyAKICAgICAgICAgICAgICAgICAgICAgICAgaXN0aWhkYW1fdHMgKyAKICAgICAgICAgICAgICAgICAgICAgICAgY29yb25hX3RzICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHQgKyAKICAgICAgICAgICAgICAgICAgICAgICAgc2Vhc29uKQoKZml0Lncuby50aWNhcmV0IDwtIHRzbG0oY29uZmlkZW5jZV90cyB+IGZhaXpfdHMgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdXJldGltX3RzICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGlzdGloZGFtX3RzICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGNvcm9uYV90cyArIAogICAgICAgICAgICAgICAgICAgICAgICB0ICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHNlYXNvbikKCmZpdC53Lm8udXJldGltIDwtIHRzbG0oY29uZmlkZW5jZV90cyB+IGZhaXpfdHMgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdGljYXJldF90cyArIAogICAgICAgICAgICAgICAgICAgICAgICBpc3RpaGRhbV90cyArIAogICAgICAgICAgICAgICAgICAgICAgICBjb3JvbmFfdHMgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdCArIAogICAgICAgICAgICAgICAgICAgICAgICBzZWFzb24pCgpmaXQudy5vLmlzdGloZGFtIDwtIHRzbG0oY29uZmlkZW5jZV90cyB+IGZhaXpfdHMgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdGljYXJldF90cyArIAogICAgICAgICAgICAgICAgICAgICAgICB1cmV0aW1fdHMgKyAKICAgICAgICAgICAgICAgICAgICAgICAgY29yb25hX3RzICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHQgKyAKICAgICAgICAgICAgICAgICAgICAgICAgc2Vhc29uKQoKZml0Lncuby5jb3JvbmEgPC0gdHNsbShjb25maWRlbmNlX3RzIH4gZmFpel90cyArIAogICAgICAgICAgICAgICAgICAgICAgICB0aWNhcmV0X3RzICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHVyZXRpbV90cyArIAogICAgICAgICAgICAgICAgICAgICAgICBpc3RpaGRhbV90cyArIAogICAgICAgICAgICAgICAgICAgICAgICB0ICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHNlYXNvbikKCmFsbCA8LSBDVihmaXQuZXZlcnl0aGluZykKbm9fZmFpeiA8LSBDVihmaXQudy5vLmZhaXopCm5vX3RpY2FyZXQgPC0gQ1YoZml0Lncuby50aWNhcmV0KQpub191cmV0aW0gPC0gQ1YoZml0Lncuby51cmV0aW0pCm5vX2lzdGloZGFtIDwtIENWKGZpdC53Lm8uaXN0aWhkYW0pCm5vX2Nvcm9uYSA8LSBDVihmaXQudy5vLmNvcm9uYSkKQ1ZfZGF0YSA8LSBkYXRhLmZyYW1lKHJiaW5kKGFsbCwgbm9fZmFpeiwgbm9fdGljYXJldCwgbm9fdXJldGltLCBub19pc3RpaGRhbSwgbm9fY29yb25hKSkKQ1ZfZGF0YQpgYGAKVGhlIG1vZGVsIGFuZCB0aGUgZGF0YSBhcmUgcGxvdHRlZCBpbiBvcmRlciB0byBzZWUgdmlzdWFsbHkgaG93IHRoZXkgYmVoYXZlLgoKYGBge3J9CmF1dG9wbG90KGNvbmZpZGVuY2VfdHMsIHNlcmllcyA9ICJEYXRhIikgKyAKICBhdXRvbGF5ZXIoZml0dGVkKGZpdC5ldmVyeXRoaW5nKSwgc2VyaWVzID0gIk1vZGVsIikKYGBgCkZyb20gdGhlIHJlc2lkdWFsIGFuYWx5c2lzIHBhcnQgd2UgY2FuIGNvbmNsdWRlIHRoYXQ6CgotICAgVGhlIHJlc2lkdWFscyBzZWVtIHRvIGhhdmUgbWVhbiB6ZXJvIGFuZCB0aGVtIHNlZW0gdG8gYmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuCi0gICBIb3dldmVyIHRoZSBkYXRhIHNob3cgdmVyeSBoaWdoIGF1dG9jb3JyZWxhdGlvbiBiZXR3ZWVuIHJlc2lkdWFscy4KCldoZW4gY29uc2lkZXJpbmcgZGlmZmVyZW50IHByZWRpY3RvcnMgd2UgY2FuIG9ic2VydmUgdGhhdCBtb3N0IG9mIHRoZSBzZWFzb25hbGl0eSB2YWx1ZXMgYXJlIG5vdCB0aGF0IGluZm9ybWF0aXZlIChXZSB3ZXJlIG5vdCBzdXJlIHdoZXRoZXIgdG8gYWRkIHRvIHRoZSBtb2RlbCkKCldoZW4gdGhlIFJlc2lkdWFscyB2cy4gRml0dGVkIHZhbHVlcyBncmFwaCBpcyBvYnNlcnZlZCwgaXQgY2FuIGJlIHNlZW4gdGhhdCB0aGUgcmVzaWR1YWxzIGFyZSBraW5kIG9mIHNjYXR0ZXJlZCBhcm91bmQgCgpPdmVyYWxsLCB0aGUgbW9kZWwgc2VlbXMgdG8gZGVvc24ndCBzZWVtIGFkZXF1YXRlIGFzIHRoZXJlIGlzIHJlYWxseSBoaWdoIEFDIGJldHdlZW4gcmVzaWR1YWxzIGFuZCB0aGUgYWRqdXN0ZWQgUl4yIHZhbHVlIGlzIHByZXR0eSBzbWFsbC4KCmBgYHtyfQpzdW1tYXJ5KGZpdC5ldmVyeXRoaW5nKQpjaGVja3Jlc2lkdWFscyhmaXQuZXZlcnl0aGluZykKCnJlc2lkdWFsX2ZpdHRlZCA8LSBkYXRhLmZyYW1lKGNiaW5kKEZpdHRlZCA9IGZpdHRlZChmaXQuZXZlcnl0aGluZyksIFJlc2lkdWFscz1yZXNpZHVhbHMoZml0LmV2ZXJ5dGhpbmcpKSkKZ2dwbG90KHJlc2lkdWFsX2ZpdHRlZCwgYWVzKHggPSBGaXR0ZWQsIHkgPSBSZXNpZHVhbHMpKSArIGdlb21fcG9pbnQoKSArIGdndGl0bGUoIlJlc2lkdWFscyB2cy4gRml0dGVkIFZhbHVlcyIpCmBgYAojIyBDb25jbHVzaW9uCgpPdmVyYWxsLCB3ZSBoYXZlIGJ1aWx0IHRocmVlIHJlZ3Jlc3Npb24gbW9kZWxzIGluIHRocmVlIGRpZmZlcmVudCB0aW1lIHNlcmllcy4gRXZlbiB0aG91Z2ggc29tZSBvZiB0aGUgbW9kZWxzIHdlcmUgYmV0dGVyIHRoYW4gdGhlIG90aGVyIG1vZGVscyB0aGVyZSB3YXMgb25lIGNvbW1vbiBwcm9ibGVtOiBhdXRvY29ycmVsYXRpb24gYmV0d2VlbiByZXNpZHVhbHMuIEluIGFsbCBvZiB0aGUgbW9kZWxzIHRoZSBBQ0YgZ3JhcGggd2FzIG5vdCBhcyBkZXNpcmVkIGFuZCB0aGlzIHJlbWFya2VkIGZ1cnRoZXIgaW52ZXN0aWdhdGlvbiBvbiB0aGUgbW9kZWwuCgpIb3dldmVyIG90aGVyIHRoYW4gdGhpcywgdGhpcyBhc3NpZ25tZW50IHRvdWdodCBob3cgdG8gYnVpbGQgbW9kZWxzLCBzZWxlY3QgcHJlZGljdG9ycywgY29tcGFyZSBtb2RlbHMgYW5kIGRvIHJlc2lkdWFsIGFuYWx5c2lzIGZvciBkaWZmZXJlbnQgdGltZSBzZXJpZXMgYW5kIHdhcyBiZW5lZml0YXJ5LgoKIyMgQXBwZW5kaWNlcwoKQ2hhdEdQVDoKCi0gSGVscCBmcm9tIExMTSBpbiBvcmRlciB0byBjcmVhdGUgZGF0YWZyYW1lcyBhZGQgYW5kIHN1YnRyYWN0IGNvbHVtbnMgYW5kIHJvd3MgYW5kIGFsc28gZm9yIGNyZWF0aW5nIGxhZ2dlZCBkYXRhLg==